Storefronts
Your own code on a component
Three ways to make a component your own, the Custom component section and its fields, Your components, the root, JS, the limits and an example.
With Advanced on you can write your own HTML, CSS and JS for a component.
Where: Customize with code at the bottom of the component panel, and New component in the Components tab. Both need Advanced.
The template syntax, the variables and the actions are under Template reference. The hooks and how the CSS is scoped are under Hooks and CSS reference.
Three ways to make a component your own
| Way | Where | What you write | Where it is saved |
|---|---|---|---|
| Your own style of a standard component | Click the component and press Customize with code. Save with Save as new style | The Design tab, CSS and JS on top of the standard markup. The Own HTML switch under Code › HTML is Off | Under Your header styles, or the matching list, in every storefront of the workspace |
| A standard component with your own HTML | The same code editor. Code › HTML with Own HTML On | The template with variables and actions, plus CSS and JS. The storefront still draws the root | The same place: a style under Your header styles |
| A completely new component | New component in the Components tab | A section with your HTML, CSS and JS. No standard markup | On the page as a section. Save to Your components puts it in the library |
With Own HTML Off you do not change the markup. Your CSS and JS sit on top of the platform's HTML. The component's options, colours and content apply as before. With Own HTML On the markup is yours and you maintain it. Start from the standard markup fills the field with the standard look's markup and turns the switch on.
BunStack saves a style in the theme draft and a new component on the page. Both go live when you publish. The storefront and the canvas draw from the same code.
New component
New component is at the bottom of the Components tab. With Advanced off, the tab shows Build a completely new component (your own HTML, CSS and JS): turn on Advanced at the top.
- Turn on Advanced.
- Select the section the new one should go after. Without a selection it goes last.
- Press New component.
- Fill in Name.
- Write the code in the HTML, CSS and JS tabs, and the fields in Fields.
BunStack puts the Custom component section on the page, selects it and opens the inspector. The same section is in the section library. You move, duplicate and hide it like other sections, see Sections and pages.
| Tab | Rule |
|---|---|
| HTML | A template with the same syntax, sanitising and actions as the components. It gets the variables storefront, brand, nav, pages, social, contact, i18n and currency, see Template reference. Variables under the field shows the list |
| CSS | Applies to the section only. The root is [data-bs-block="<section-id>"]. h2 { … } becomes [data-bs-block="…"] h2 { … } and & { … } applies to the root itself |
| JS | Runs once per page load with the section's root as root. The Run JS in the builder switch applies here too |
| Fields | The fields the inspector shows to everyone, as JSON. See Fields |
What the template or the CSS does not let through shows in red under the code while you type. With Advanced off, the inspector shows the name, the fields, Width, Show on, Background and the text Edit in Advanced mode. The section renders in the storefront as usual.
Fields
Fields let anyone change a component's texts, colours and products without code. You write the fields as JSON in the Fields tab. The values are changed in the inspector under WORDS & PICTURES, also with Advanced off.
[
{ "key": "heading", "type": "text", "label": "Heading" },
{ "key": "items", "type": "list", "label": "Items", "fields": [
{ "key": "name", "type": "text", "label": "Name" },
{ "key": "text", "type": "richtext", "label": "Text" },
{ "key": "colour", "type": "colour", "label": "Colour" },
{ "key": "product", "type": "product", "label": "Product" }
] }
]
key is the name the template reads: letters, digits and _, a letter first. label is the name in the inspector.
| Type | The value | In the template |
|---|---|---|
text | A line of text | {{fields.heading}} |
richtext | Formatted text, written in the text editor | The words, without formatting. The formatted text goes in an empty element with data-bs-field-html |
colour | A colour, #rrggbb | {{colour}} inside the list, for example in style |
product | A product in the storefront | {{product.title}}, {{product.url}} and {{product.image}}. Empty when the product is not in the storefront |
list | Items with the fields under fields. A list cannot hold a list | {{#each fields.items}} … {{/each}} |
<h2>{{fields.heading}}</h2>
{{#each fields.items}}
<article style="border-top: 3px solid {{colour}}">
<h3>{{name}}</h3>
<div data-bs-field-html="items.{{@index}}.text"></div>
{{#if product}}<a href="{{product.url}}">{{product.title}}</a>{{/if}}
</article>
{{/each}}
- At most 20 fields, 12 in a list and 24 items in a list.
- What is wrong in the JSON shows in red under the field.
- Save to Your components saves the fields with their values. A copy put on a page gets the values.
- The section's Width, Show on and Background are in the inspector as on every section, under LAYOUT and LOOK. See Width and Background.
Your components
Save to Your components at the bottom of the inspector saves the section in the workspace's library: name, HTML, CSS, JS and the fields. The notice says, for example, Saved "Hero video" to Your components. The section is now linked to that row in the library, and the buttons change:
- Update "Hero video" overwrites the row with the section's content. Copies added afterwards get the new one. Copies already on pages do not change.
- Save as new saves a new row. The section is then linked to the new row.
- Remove from Your components removes the row from the library.
Remove a saved component:
- Press Remove from Your components.
- Read Remove "Hero video" from Your components? Copies already on pages stay. Press Continue, or Keep to stop.
- Type the name in the field under Type Hero video to confirm. Upper or lower case does not matter.
- Press Remove "Hero video".
The row leaves the library in every storefront of the workspace. You cannot undo it. The copy on the page stays. If someone else removed the row before you press Update, the inspector shows That component is no longer in Your components. Save it as new. and drops the link.
A saved component is listed in every storefront of the workspace:
- in the section library as the Your components row, under the ALL category
- in the Library tab as a group of its own
- in ⌘K as Add "Hero video"
The search finds it by name. The words your and components list all of them. A click puts a copy on the page. You can add the copy with Advanced off, but you can change the code only with Advanced on.
The root is the storefront's
A component has a root that the storefront draws. Your template is the content of the root. The header's root is [data-bs-header]. The storefront sets the states [data-bs-transparent], [data-bs-scrolled] and [data-bs-sticky] on the root, even when the header is your own HTML.
Do not write a <header> of your own in the template. Start with what goes inside. Your CSS is scoped to the root and your JS gets the root as root. All roots are under Hooks and CSS reference.
JS
- The JS runs once per page load, when the page has loaded.
- It runs on every page where the component exists, with the component's root as
root. - The menu panel's root exists only while the panel is open. Its JS runs each time the panel opens. Bind listeners on
root, not ondocument. - A product card appears several times on a page.
rootis the first one. Usedocument.querySelectorAll('[data-bs-card]')for all. - An error goes to the browser console with the style's name. The error stops neither the page nor other components' JS.
- Turn off Run JS in the builder above the JS field to pause your JS on the canvas for the session. The storefront and Preview (⌘P) in the designer still run it.
root.querySelectorAll('[data-bs-header-icons] a').forEach((a) => {
a.addEventListener('mouseenter', () => a.classList.add('is-hot'));
});
The page's JS in the Code panel runs the same way, without root. JS on the Collection page applies to every category page.
Limits
| Field | Max |
|---|---|
| The HTML template and what it renders | 200 000 characters |
| CSS | 200 000 characters |
| JS | 100 000 characters |
| Fields (JSON) | 20 000 characters |
BunStack cuts longer code and shows a warning that says where. Template reference describes the errors and warnings.
Example: transparent header with icons
The goal is a full-width header. It is transparent over the hero image with a white logo and white icons. After 24 px of scrolling it turns solid. On the right are 4 icons of 30 px: search, wishlist, cart and menu.
Do this on the component panel for Header:
- Put an Image banner with Width Full and a dark photo first on the home page.
- Look: choose Icons + panel.
- Options: turn on Sticky and Transparent over hero. Turn off Menu label and Announcement bar.
- Content: choose the dark logo under Logo, height 40. Choose the white one under Light logo.
- Check that Theme › Colours › Header text over hero is white.
- Choose fonts and base size under Theme › Typography.
Advanced on, Customize with code, Code › CSS:
[data-bs-header] { padding: 16px; }
@media (min-width: 768px) { [data-bs-header] { padding: 32px; } }
[data-bs-header-inner] { max-width: none; }
[data-bs-header-icons] { gap: 16px; }
[data-bs-header-icons] a, [data-bs-header-icons] button { opacity: 1; }
[data-bs-header-icons] svg { width: 30px; height: 30px; stroke-width: 1.6; }
Press Save as new style and name it "My navbar". It is now under Your header styles in every storefront of the workspace. The style contains the look, the options, the Design tab and the CSS. The logos belong to the theme. Set them under Content in each storefront.
The same header written as your own HTML is under Template reference.