---
name: vizen-widgets
description: Configure Vizen's built-in blocks — header, menu, footer, product listing, product card, covers, cards, slideshow — through their props, and know where their limits are. Use when the shop should look tidy and branded rather than fully bespoke, or when live catalogue data matters more than a custom design.
---

# Platform widgets

The fast path: live data, working sticky header, working dropdowns, filters and
paging — at the price of a look bounded by props.

## 1. Where the truth about props lives

```
GET /docs/widgets
```

Generated from the real widget parsers, so it cannot drift from the platform. For
each kind: label, whether it is chrome or a page block, **the write path**, a
JSON Schema of its props with defaults, and the allowed values of every enum.

Read the schema of the kind you are about to change. Do not write a prop from
memory: an unknown value is accepted and the default is drawn.

## 2. The write path is where agents go wrong

Props are nested per widget: `props.listing.…`, `props.card.…`, `props.form.…`.
The reference states `writePath` for each kind — use it. Writing to the root of
`props` is accepted and does nothing.

`sections` is a **replace-set**: read the block, change the one element, send the
whole list back. Sending a single section deletes the rest.

## 3. The wrapper is configurable too — and it is how you reskin a widget

Every block sits in a standard wrapper, and its axes are written next to `kind`,
at the root of `props`, not inside the widget's own path. Ask for the current
list rather than trusting any copy of it — one that named a `props.innerMax`
nothing had ever read survived for weeks:

```bash
curl -s https://api.vizen.shop/docs/widgets | jq -r '
  .wrapper.axes[] | [.path, .type, (.default // "-"), .anchor.at] | @tsv'
```

Each row carries the `file:line` in the storefront that sets the default, and
`.wrapper.elements` does the same for the two wrapper divs themselves.

**When the props run out, the wrapper is the next move, not own markup.**
`props.wrapperClass: "my-hero"` puts your own class on the band — including the
band of `siteHeader`, `siteMenu` and `siteFooter` — and you restyle it from your
own CSS (`.my-hero > .vz-inner { … }`). You keep the working widget, its live
data and its props, and change only the look. Two catches: the CSS has to live in
a **level 3** document (level-1 styles are trapped in a shadow root), and you must
never target the platform's own class names directly. Recipe:
`GET /docs/own-markup` §5, skill `vizen-own-markup`.

Per-device overrides live under `props.tablet` and `props.mobile`, same keys.

## 4. Known limits — say them out loud before promising a look

- the listing's own strip cannot be recoloured today: `container.fill` on
  `productListing` is accepted and does nothing;
- the listing template is `default` and there are no others;
- `siteMenu.level2` builds a real dropdown from your category tree — it opens
  **on click**, not on hover, whatever the field description says;
- some style props are clamped: a font weight of 800 renders as 600, a label size
  of 13 renders as 15.

If the owner wants something outside these bounds, that is the fork into
`vizen-own-markup` — and it costs live data in product rows. Say so.

## 5. Validate before writing

`POST /docs/validate` with the sections you are about to send. It replies per
path whether the value will be applied, silently ignored, or not understood —
which is exactly the class of mistake this area produces most. Nothing is
written.

## 6. Verify

Re-read the block and open the page. A 200 is not evidence. Full checklist:
`vizen-troubleshoot`.
