# Render a metafield yourself

> Write a metafield value with your own code, with the smootify.devMetafield event that fires after Smootify's render, and render a list metafield from smootify.renderedMetafields.

Status: Ready (Smootify 2.0)  
1.x page: https://docs.smootify.io/docs/ecommerce/products/metafields  
URL: https://www.smootify.io/docs/developers/custom-metafields  
Updated: 2026-10-01

Smootify 2.0 renders every Shopify metafield type by itself, lists, JSON and references included. When a design needs a different output, a script can take over. This page shows the event that hands a single value to your code, and how to render a list yourself.

> [!NOTE]
> Check first whether an attribute already gives the output you need: `separator` for lists, `data-path` for JSON, `[reference]` for references. See [Metafields on the page](https://www.smootify.io/docs/build/metafields) and [metafield types](https://www.smootify.io/docs/reference/metafield-types).

## The `smootify.devMetafield` event

Smootify sends `smootify.devMetafield` on `document` right after it has written a metafield into an element. What your listener writes into the element stays: your code has the last word.

- **`event.detail`** is `{ element, metafield }`. `element` is the element with the metafield attribute; `metafield` is `{ namespace, key, type, value, reference, references }`, with `value` as Shopify sends it (a string, JSON for structured types).
- **Weight and volume** also carry `jsonValue`, the value already parsed (`{ value, unit }`).
- **It fires for every metafield attribute**: `metafield`, `variant-metafield`, `customer-metafield`, `company-metafield`, and the fields of a metaobject.
- **It fires only when the metafield has a value** on that product, variant or customer.

It fires for these types only:

- `json`, `weight`, `volume`;
- `product_reference`, `variant_reference`, `collection_reference`, `page_reference`, `mixed_reference`;
- the lists `list.number_integer`, `list.number_decimal`, `list.date`, `list.date_time`, `list.dimension`, `list.volume`, `list.weight`, `list.color`, `list.url`, `list.rating`, `list.product_reference`, `list.variant_reference`, `list.collection_reference`, `list.page_reference`, `list.mixed_reference`.

The other types, such as text, numbers, rich text, files, `rating` and metaobject references, are rendered by Smootify with no event.

The event name has no `smootify:` prefix, so `Smootify.on` cannot listen to it: use `document.addEventListener`. Register the listener in the Head code, or in a `push` function, so it is there before the first product renders.

## Example: a JSON value

A JSON metafield `custom.dimensions` holds `{"width": 60, "depth": 40}`. The designer puts `metafield="dimensions"` on a Text block. Without `data-path`, Smootify leaves an object as it is, and your code writes it:

```js
document.addEventListener("smootify.devMetafield", (event) => {
  const { element, metafield } = event.detail;
  if (metafield.key !== "dimensions") return;
  const { width, depth } = JSON.parse(metafield.value);
  element.textContent = `${width} × ${depth} cm`;
});
```

Variant metafields render again at every variant change, and the event fires again each time. Write the listener so it can run many times on the same element.

## Lists

What your listener writes into `element` shows only when the metafield fills one element:

| The metafield | `element` in the event | What you write into it |
|---|---|---|
| `json`, `weight`, `volume`, a reference, or a list of numbers, dates or measures joined into one text (`60 cm, 80 cm, 120 cm`) | the element on the page | shows: your code has the last word |
| a list of colors, URLs, ratings or references, or another list with `separator="repeat"`: one copy per value | the template, which Smootify took out of the page for the copies | does not show: render the list from `smootify.renderedMetafields` |

To render a list yourself:

1. Put an attribute of your own on the element that holds the list, such as `data-features`, not `metafield`.
2. Ask Shopify for the metafield with the [`metafield_definitions`](https://www.smootify.io/docs/developers/filters) filter, since no `[metafield]` element asks for it now.
3. Write the list when `smootify.renderedMetafields` fires.

`smootify.renderedMetafields` goes out on `document` each time Smootify has rendered the metafields of an element. `event.detail` is `{ context, attribute, metafields }`: `context` is that element (a `smootify-product`, a `cart-item`…), `attribute` the kind (`metafield` for a product’s metafields, `variant-metafield` for its variant’s), and `metafields` the values Shopify sent.

```js
window.Smootify = window.Smootify || [];
window.Smootify.push((Smootify) => {
  Smootify.addFilter("metafield_definitions", (definitions, { scope }) =>
    scope === "product" ? [...definitions, { namespace: "custom", key: "features" }] : undefined,
  );
});

document.addEventListener("smootify.renderedMetafields", (event) => {
  const { context, attribute, metafields } = event.detail;
  if (attribute !== "metafield" || !(context instanceof Element) || !context.matches("smootify-product")) return;
  const list = context.querySelector("[data-features]");
  const features = metafields?.find((m) => m?.namespace === "custom" && m.key === "features");
  if (!list || !features?.value) return;
  list.replaceChildren(
    ...JSON.parse(features.value).map((text) => {
      const item = document.createElement("li");
      item.textContent = text;
      return item;
    }),
  );
});
```

The same pattern works for a single value that no attribute shows.

## Where people get stuck

> [!STUCK]
> - **The listener never runs.** It was added with `Smootify.on`: use `document.addEventListener`. Or the type is one Smootify renders without the event, such as a text or a `rating`.
> - **Nothing changes on a list.** The list makes one copy per value, and the event's `element` is the template, no longer on the page. Render the list from `smootify.renderedMetafields`.
> - **It works on one product and not on another.** The event fires only when that product has a value for the metafield.
> - **The metafield never reaches the page.** In Shopify, its definition needs Storefront access. Without any element or filter asking for it, Smootify does not request it either.
> - **What the script wrote is gone after a variant change.** Variant metafields render again at every change and the event fires again: do not stop the listener after its first run.

## Coming from 1.x

In 1.x, lists, JSON and references were left to custom code through `smootify.devMetafield`. 2.0 renders them, and the event still fires for them, after the render: a script that writes a single value keeps working. A script that filled a list element must move to `smootify.renderedMetafields`, as above. Weight and volume now print the unit symbol (`650 g`) before the event, so a script that reads the element’s text sees the new format.
