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.
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 and 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.detailis{ element, metafield }.elementis the element with the metafield attribute;metafieldis{ namespace, key, type, value, reference, references }, withvalueas 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:
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:
One element on the page
- Types
json,weight,volume, the references, and lists of numbers, dates and measures joined into one text.- Your text
- Shows: your code has the last word.
One copy per value
- Types
- Lists of colors, URLs, ratings and references, and the other lists with
separator="repeat". - Your text
- Does not show.
Render the list from smootify.renderedMetafields instead.
To render a list yourself:
- Put an attribute of your own on the element that holds the list, such as
data-features, notmetafield. - Ask Shopify for the metafield with the
metafield_definitionsfilter, since no[metafield]element asks for it now. - Write the list when
smootify.renderedMetafieldsfires.
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.
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
Check these first
- The listener never runs. It was added with
Smootify.on: usedocument.addEventListener. Or the type is one Smootify renders without the event, such as a text or arating. - Nothing changes on a list. The list makes one copy per value, and the event’s
elementis the template, no longer on the page. Render the list fromsmootify.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.