1. Pick the right product shape
| Name | Type | Description |
|---|---|---|
Primitive on the page | prefer | Single heading, image, link, or form value — do not package as a Store component. |
Content block | presentation | Structure + behavior; inherits host design. Best default for reusable sections. |
Styled widget | presentation | Ships its own look via design fields / CSS variables. Be honest in the listing. |
Items slot component | pattern | Editors grow a list (slides, cards). Shell settings stay in fields[]. |
2. Design for hosted buyers first
Most Store installs run your hosted bundle. Buyers cannot fork your CSS unless they purchase code access. Design through:
fields[]the overlay can edit (content + optional design group).- CSS variables / tokens the host can override when you document them.
- Items slots for structure editors must grow (slides, cards, FAQ rows).
- Project slots only when the site developer must drop arbitrary HTML into a region (rare for pure Store widgets).
3. Recommended architecture
Shell settings in fields
Autoplay, interval, layout mode, density — small JSON payload. Keep labels buyer-friendly; they appear in the overlay.
fields: [ { key: 'autoplay', label: 'Autoplay', input: 'boolean', group: 'content' }, { key: 'intervalMs', label: 'Interval (ms)', input: 'number', group: 'content' }, ]Repeating content in items slots
Each slot field becomes a real primitive node (inline editable). Editors get Add / Remove / Reorder for free — no custom sidebar required.
slots: [ { name: 'slides', kind: 'items', label: 'Slides', min: 1, max: 12, fields: [ { field: 'image', type: 'image', label: 'Image' }, { field: 'headline', type: 'text', label: 'Headline' }, { field: 'body', type: 'richtext', label: 'Body' }, { field: 'cta', type: 'link', label: 'Call to action' }, ], }, ]render() builds chrome + mounts regions
Use
mountSlotRegionfor items. Cache-aware: safe to clear the host and re-append the returned region. Observe[data-macro-repeater-item]if you need nav dots derived from the DOM.import { macroSlotField, mountSlotRegion } from '@macrocontent/sdk' function buildSlide(doc: Document): HTMLElement { const article = doc.createElement('article') const img = doc.createElement('img') Object.entries(macroSlotField('image', 'image')).forEach(([k, v]) => img.setAttribute(k, v), ) const h3 = doc.createElement('h3') Object.entries(macroSlotField('headline', 'text')).forEach(([k, v]) => h3.setAttribute(k, v), ) article.append(img, h3) return article } const region = mountSlotRegion({ host, mountTarget: viewport, name: 'slides', kind: 'items', seed: 3, max: 12, buildItem: () => buildSlide(host.ownerDocument), })Inline affordances on visible content
Apply
macroSlotField/macroFieldAttr/macroAssetFieldAttrso editors click on the page. For carousels, mark the visible item so image context actions hit the right slide.
4. Content-block CSS rules
.my-block {
color: inherit;
font: inherit;
}
.my-block__accent {
color: var(--macro-accent, currentColor);
}
.my-block__card {
border-radius: var(--macro-radius, 0.5rem);
}Do
- Inherit typography and color from the host.
- Expose 1–3 tokens max (
--macro-accent,--macro-radius). - Use
currentColorfor icons and borders when possible.
Don’t
- Don’t hardcode brand purples/oranges that fight the customer site.
- Don’t ship a full design system inside a “content” listing.
- Don’t hide critical content behind hover-only UI without keyboard access.
5. Styled-widget rules
- Put theme / accent / radius (and similar) in
group: 'design'so editors find them under a Design sub-tab. - Drive the look from CSS variables set in
render()from the payload. - Still avoid baking customer content into the bundle — images and copy come from Macro assets / fields / slots.
fields: [
{ key: 'title', label: 'Title', input: 'text', inline: true, group: 'content' },
{
key: 'theme',
label: 'Theme',
input: 'select',
group: 'design',
options: [
{ value: 'light', label: 'Light' },
{ value: 'dark', label: 'Dark' },
],
},
{ key: 'accent', label: 'Accent', input: 'text', group: 'design' },
{ key: 'radius', label: 'Radius', input: 'text', group: 'design' },
]6. typeId, tag, and packaging
- Declare a namespaced
typeId(@your-brand/my-slider). Macro derives the custom element tag for Store bundles. - Keep
defaultPayloaddemo-ready — empty installs should still look intentional. - Ship gallery / preview assets that match the runtime. The Store can embed website + editor demos so buyers try inline edit before installing.
- Run the bundle through validation before publish — see Bundles & Macro Score.
7. Quality bar (what buyers notice)
| Name | Type | Description |
|---|---|---|
Honest presentation | score | Listing claim matches CSS reality (content vs styled). |
Editable structure | ux | Items slots (or clear fields) instead of frozen placeholder copy. |
Inline where it matters | ux | Headlines and images editable on the page, not only in a JSON dump. |
Clean bundle | security | No secrets, no forbidden scanner patterns, no surprise network calls. |
Preview fidelity | store | Gallery and demos match what install + editor actually show. |
8. Local → Store workflow
- Build and register locally with Custom components.
- Exercise draft/live, locales, assets, and slots with a real editor account.
- Package the bundle; fix Macro Score findings (forbidden patterns, presentation drift).
- Complete the listings wizard (presentation, pricing, previews).
- Publish a release — Releases & updates.