# Dynamic properties

> Fields the customer fills before adding to the cart, such as an engraving or a choice, decided product by product in Shopify and written once in the product component.

Status: Ready (Smootify 2.0)  
Add-on: Dynamic Properties  
URL: https://www.smootify.io/docs/astro/features/dynamic-properties  
Updated: 2026-10-21

Dynamic properties are the questions a product asks before it goes to the cart: the text to engrave, a name and number for a shirt, a delivery time, a confirmation box. The merchant decides in Shopify which product asks what. In the product component you write each kind of field once, and each product shows only its own. The answers travel with the cart line to the order.

> [!NOTE]
> Turn on **Dynamic Properties** in the Smootify dashboard. It is free. It adds the **Dynamic Property** metaobject definition and the **Dynamic Properties** product metafield to Shopify. In Shopify, under **Settings > Custom data**, check that both have **Storefront access**: Smootify creates them with it, but a definition that already existed in the store keeps its own setting.

Properties are not variant options. Options make variants, with their own price, SKU and stock. A property changes nothing about the product: it only records the customer’s answer. To make an answer change the price, see the [product configurator](https://www.smootify.io/docs/astro/features/product-configurator).

## 1. Create the properties in Shopify

In Shopify, go to **Content > Metaobjects > Dynamic Property** and create one entry per question. Its fields:

| Field | What it does |
|---|---|
| **Title** | links the entry to the markup: it is the `label` of the element. It is also shown as the field’s label |
| **Property Name** | the name the answer is saved under, shown in the cart, at checkout and on the order |
| **Property Type** | Text, Number, Email, Url, Select, Dropdown, Radio, Checkbox or Swatches |
| **Placeholder** | the placeholder of a text field, or the first, empty entry of a select or dropdown |
| **Values** | the choices of a Select, Dropdown, Radio or Swatches property |
| **Images** | for Swatches: one image per value, in the same order as **Values** |
| **Required?** | the customer must answer before adding to the cart |
| **Custom attributes for the input** | extra rules for a text field, one entry per rule, written `name:value`, such as `maxlength:20` or `min:1` |

On stores set up with an earlier version, the **Title** field may be called **Label**: it works the same way.

Then open each product and pick its properties in the **Dynamic Properties** metafield.

## 2. Add the fields

In the component of the product page, inside the `<form>` of `smootify-add-to-cart`:

1. Add the element `dynamic-property`.
2. Give it the attribute `label`, with the **Title** of the Shopify entry, written exactly the same.
3. Inside it, put the element its type needs (see below).

```html
<dynamic-property label="Engraving">
  <label>Engraving</label>
  <input name="engraving">
</dynamic-property>
<dynamic-property label="Finish">
  <label>Finish</label>
  <button>Value</button>
</dynamic-property>
```

Smootify gives the field the **Property Name**, the placeholder, the **Required?** setting and the attributes from Shopify. A `label` inside the element takes the **Title** as its text. You design the rest.

**Design once for every product.** Add one `dynamic-property` for each property your products may use. On a product that does not have that property, the element is removed. With `delete-parent`, its parent element is removed instead: use it when the field sits in a wrapper with its own heading or spacing.

### The element for each type

Each **Property Type** needs its own element inside `dynamic-property`:

| Property Type | Put inside `dynamic-property` | How it shows the choices |
|---|---|---|
| Text, Number, Email, Url | an `input`, with its `type` | the Placeholder is the input’s placeholder |
| Select | a `select` | Smootify writes its options. The Placeholder, when set, is the first entry, with no value |
| Dropdown | a `[popover]` with its trigger, a `button` with `popovertarget` | the first link or button inside the popover is the template of every value; the trigger shows the choice. The Placeholder, when set, is the first, empty entry |
| Radio | one `<label><input type="radio"><span form-label>…</span></label>` | it is the template of every value; its `[form-label]` takes each value |
| Checkbox | one `<label><input type="checkbox"><span form-label>…</span></label>` | its `[form-label]` takes the **Title**; when checked, the answer is saved as ✓ |
| Swatches | one `button` | it is the template of every value: an element with `option="title"` inside it gets the value, an `img` with `option="image"` the value’s image from **Images**. Without an `option="title"` element, the value replaces everything inside the button. The chosen button gets the class `is-active` |

For the popover, see [popovers](https://www.smootify.io/docs/astro/build/popovers). A required Dropdown or Swatches property left empty gives the class `is-invalid` to the element that shows it, so you can style the error.

**Show the answer elsewhere.** A text element with the attribute `form-value` and the field’s `name`, inside the same `smootify-product`, shows the answer as the customer types, such as the recipient’s name on a gift card preview: a text element with `form-value="Recipient name"` after “for”. Give it `data-fallback="Anna"` to show a sample name until the customer writes one. For a choice, it shows the chosen label. It reads any field of the add to cart form, a plain field as well as a dynamic property.

## 3. What reaches the order

The answer is saved on the cart line under the **Property Name**. It shows in the [cart](https://www.smootify.io/docs/astro/build/cart), at checkout and on the order in Shopify.

**Hidden properties.** A **Property Name** that starts with `_`, such as `_production_code`, is saved on the order but not shown in the cart or at checkout. Use it for data the merchant needs and the customer does not.

Developers can check or complete the answers before they reach the cart, for example to reject an engraving that is too long: see [filters](https://www.smootify.io/docs/astro/developers/filters).

## Before you publish

> [!STUCK]
> - **No property shows.** The definitions are missing because Dynamic Properties was never turned on, or the metafield or the metaobject definition has no Storefront access, or the product's **Dynamic Properties** metafield is empty.
> - **One property never shows.** Its `label` is not written exactly like the entry's **Title**.
> - **The answer is not in the cart.** The `dynamic-property` is outside the `<form>`, or the entry has no **Property Name**.
> - **A choice property is empty.** The entry's **Values** field is empty.
> - **Swatch images are mixed up.** The **Images** are not in the same order as the **Values**.
> - **The field disappears on some products.** That is expected: those products do not have the property. Add `delete-parent` to remove its wrapper too.
