Storefronts
Hooks and CSS reference
The hooks in the storefront's HTML per component, the hooks on the page, how component CSS is scoped and what CSS sanitising removes.
The hooks are attributes in the storefront's HTML that your CSS can target.
Where: Used in Code › CSS in the code editor, in the Code panel and in Theme › Custom CSS. See Your own CSS and head code.
The template syntax, the variables and the actions for your own HTML are under Template reference.
The hooks per component
A hook does not change its name unless this table changes too. Each component has three kinds of hooks:
- a root, that the component's CSS is scoped to and that the JS gets as
root - inner elements
- states, which the storefront sets on the root to show the mode
A state is written on the root: [data-bs-header][data-bs-transparent], not as a child.
| Component | Hook | Type | Values | What |
|---|---|---|---|---|
| Header | [data-bs-header] | root | The header on every page | |
| Header | [data-bs-header-inner] | inner | The row inside the header: the page width on Page, out to the side margin on Full | |
| Header | [data-bs-logo] | inner | The logo link. On a narrow phone it shrinks so the icons and the menu button stay on screen | |
| Header | [data-bs-header-nav] | inner | start, end | The link row in Logo left and Centered. Split has two halves |
| Header | [data-bs-header-icons] | inner | The icon row in the Icons + panel layout | |
| Header | [data-bs-menu-button] | inner | The button that opens the menu panel | |
| Header | [data-bs-cart-icon] | inner | The cart icon | |
| Header | [data-bs-cart-count] | inner | The item count next to the cart icon, kept live | |
| Header | [data-bs-wishlist-icon] | inner | The wishlist icon | |
| Header | [data-bs-announcement] | inner | The announcement bar above the header | |
| Header | [data-bs-transparent] | state | Set on the home page while Transparent over hero is on | |
| Header | [data-bs-scrolled] | state | Set after 24 px of scrolling, and while the menu panel is open (transparent header only) | |
| Header | [data-bs-sticky] | state | Set while Sticky is on | |
| Header | [data-bs-header-width] | state | page, full | The Width option: page lines the row up with the page content, full runs it out to the side margin |
| Menu panel | [data-bs-menu] | root | The panel that opens from the header | |
| Menu panel | [data-bs-menu-layout] | inner | split, mega | The panel's grid: Shop + information (split) or Links, products, contact (mega) |
| Menu panel | [data-bs-menu-links] | inner | The list of big links | |
| Menu panel | [data-bs-menu-link] | inner | A big link. Its line height follows its font size. data-active marks the link the cards follow, aria-current the page the customer is on | |
| Menu panel | [data-bs-menu-secondary] | inner | The list of small links | |
| Menu panel | [data-bs-menu-products] | inner | The product column beside the links (Links, products, contact) | |
| Menu panel | [data-bs-menu-heading] | inner | The heading over the products, when one is set | |
| Menu panel | [data-bs-menu-cards] | inner | The cards. The set changes with the active link | |
| Menu panel | [data-bs-menu-contact] | inner | The contact bar at the bottom of the panel | |
| Footer | [data-bs-footer] | root | The footer on every page | |
| Footer | [data-bs-footer-inner] | inner | The row inside the footer: the page width on Page, out to the side margin on Full | |
| Footer | [data-footer-column] | inner | brand, shop, help, legal | One footer column |
| Footer | [data-bs-footer-links] | inner | The link list in a column. Where the tokens CSS sets the links' size and opacity | |
| Footer | [data-bs-footer-social] | inner | The social links in the bottom row. Where the tokens CSS draws their squares | |
| Footer | [data-footer-copyright] | inner | The copyright line | |
| Footer | [data-bs-footer-width] | state | page, full | The Width option, as on Header |
| Product card | [data-bs-card] | root | One product in a grid. Everywhere products are listed | |
| Product card | [data-bs-card-media] | inner | The photo plate | |
| Product card | [data-bs-card-hover] | inner | The second photo shown on hover | |
| Product card | [data-bs-card-body] | inner | Title, tag line and price | |
| Product card | [data-bs-card-title] | inner | The title | |
| Product card | [data-bs-card-meta] | inner | The tag line under the title | |
| Product card | [data-bs-card-price] | inner | The price row | |
| Product card | [data-bs-card-variant] | state | card, plate, editorial | The card's surface |
| Product page | [data-bs-product-layout] | root | classic, split | The product page: gallery and buy panel |
| Product page | [data-bs-product-info] | inner | The buy panel: title, price, options, add to cart | |
| Product page | [data-bs-swatch] | inner | A colour swatch in the variant picker | |
| Product page | [data-bs-cta="primary"] | inner | Add to cart and the other primary buttons | |
| Product page | [data-bs-image-side] | state | left, right | Which side the gallery sits on (Split layout) |
| Gallery | [data-bs-gallery] | root | The product images on the product page | |
| Collection page | [data-bs-category] | root | A collection page: a category, All products or search results | |
| Collection page | [data-bs-category-header] | inner | The band with the category name | |
| Collection page | [data-bs-category-header-inner] | inner | The column inside the band | |
| Collection page | [data-bs-collection-body] | inner | The filters and the grid. From Desktop the sidebar sits beside the grid | |
| Collection page | [data-bs-filters-layout] | inner | sidebar, top, none | How the page lays out the filters |
| Collection page | [data-bs-filters] | inner | The filters, in a sidebar or in a row, from Desktop | |
| Collection page | [data-bs-filters-mode] | inner | top, sidebar | How the filters are laid out |
| Collection page | [data-bs-sticky] | inner | Set on the filters and the bar while Filters stay in view is on. On the row only while its filters fit on one line | |
| Collection page | [data-bs-stuck] | inner | Set on the row and the bar while they rest under the header | |
| Collection page | [data-bs-facet] | inner | One filter in the row above the grid: its button and its list | |
| Collection page | [data-bs-facet-panel] | inner | The list of values that opens under a filter button | |
| Collection page | [data-bs-open] | inner | Set on the filter whose list is open (one at a time), and on an open group | |
| Collection page | [data-bs-facet-group] | inner | One group in the sidebar and the phone panel: its name and its values | |
| Collection page | [data-bs-facet-toggle] | inner | The group's name, which folds the group | |
| Collection page | [data-bs-facet-body] | inner | The part of a group that folds | |
| Collection page | [data-bs-facet-values] | inner | A group's values. Past 240 px they scroll inside the group | |
| Collection page | [data-bs-facet-value] | inner | One value: its box, its name and its count | |
| Collection page | [data-bs-on] | inner | Set on a ticked value | |
| Collection page | [data-bs-count] | inner | The count after a value | |
| Collection page | [data-bs-clear-filters] | inner | Clear filters (n), at the top of the sidebar | |
| Collection page | [data-bs-cta="primary"] | inner | Clear filters in the row; Show N products in the phone panel | |
| Collection page | [data-bs-filter-bar] | inner | count | The bar over the grid: the count and Sort. On phones and tablets also Filters (n). count when it has neither: the count alone, a line of text on every screen |
| Collection page | [data-bs-filter-open] | inner | Filters (n), on phones and tablets | |
| Collection page | [data-bs-result-count] | inner | How many products the page lists | |
| Collection page | [data-bs-sort] | inner | The sort control | |
| Collection page | [data-bs-filter-panel] | inner | The phone and tablet panel, over the page | |
| Collection page | [data-bs-filter-sheet] | inner | The panel itself, from the left | |
| Collection page | [data-bs-filter-shade] | inner | The shade behind the panel | |
| Collection page | [data-bs-closing] | inner | Set on the panel while it slides out | |
| Banners | [data-bs-banner] | root | An image banner among the page's sections | |
| Banners | [data-bs-banner-inner] | inner | The copy column over the image | |
| Banners | [data-bs-banner-heading] | inner | The heading | |
| Banners | [data-bs-banner-subtitle] | inner | The subtitle | |
| Banners | [data-bs-cta] | inner | primary, light, outline | The button |
| Banners | [data-bs-banner-img] | inner | The photo of a banner without text. Its height cap follows the screen | |
| Banners | [data-bs-banner-size] | state | xs, sm, md, lg, xl, screen | The height preset on a desktop |
| Banners | [data-bs-banner-size-tablet] | state | xs, sm, md, lg, xl, screen | The height preset on a tablet: its own, or the desktop one |
| Banners | [data-bs-banner-size-mobile] | state | xs, sm, md, lg, xl, screen | The height preset on a phone: its own, or the tablet one |
| Banners | [data-bs-bleed] | state | full, custom | Full: the banner runs edge to edge. Custom: a width other than the page |
The hooks on the page
| Hook | What |
|---|---|
[data-bs-main] | The content column between header and footer. Its width is --bs-content-max and its side margin --bs-gutter |
[data-bs-block="<section-id>"], #bs-<section-id> | A section on any page. Works as an anchor for links. The root for CSS and JS in a Custom component section |
[data-bs-section-width] | A section's width, on the section's wrapper: page, xs, sm, md, lg, xl, 2xl, full or custom. The width worked out is in --bs-sec-w |
[data-bs-hide~="mobile"] | A section hidden on a phone (Show on). The values are desktop, tablet and mobile, separated by spaces |
[data-bs-first-on~="mobile"] | The first section shown on a phone when the first section is hidden there. The values are desktop, tablet and mobile, separated by spaces |
[data-bs-video-frame] | The player in a Video section. --bs-video-ratio is the video's width over its height, for example 1.7778 for 16:9 |
[data-bs-grid-more] | The "View all" link in a product row |
[data-bs-grid] | The grid in Product grid, Categories, Gallery, Testimonials, Stats, Cards, Collection list and Recently viewed. The columns per screen (Per screen size) are in --bs-cols, --bs-cols-tablet and --bs-cols-mobile. grid-template-columns on the hook wins without !important |
[data-bs-cta="secondary"] | The Load more button under a product grid |
[data-bs-section-tone] | A section whose Background is not Page. The value is light, dark, brand or custom. The colours are in --bs-tone-bg and --bs-tone-fg, the vertical padding in --bs-tone-pad |
[data-bs-cards], [data-bs-cards-item] | The Cards section, with the value grid or rows, and one card in it. The card look is in [data-bs-cards-look]: plain, panel or panel-line |
--bs-main-pad | The content column's vertical gutter, 2.5rem. margin-top: calc(-1 * var(--bs-main-pad)) pulls a section flush under the header |
--bs-content-max | The page width from Theme › Layout, for example 1024px |
--bs-gutter | The side margin: 16px on a phone, 24px on a tablet and 32px on a desktop |
[data-bs-legal-line] | The row with the withdrawal link under a custom footer, or on a page without a footer. [data-bs-legal-line-inner] is the row inside |
--bs-header-offset | The header's height while it stays in view as the page scrolls, 0 otherwise. The collection pages' filters sit under it with Filters stay in view |
Rules in the tokens CSS
These are rules in the tokens CSS, not inline styles on the elements:
- the header's padding, colour, background and border
- the footer's links
- the banner's heading, subtitle, height and corners
- the banner button's colours
- the product card's plate and photo corners
- the columns of the grids, per screen
- the page width and side margin, the header and footer rows and the sections' width
- the screens a section shows on, and the banner's height per screen
- the collection pages' filters: the sidebar, the row and the slim bar on phones and tablets
A plain rule on the hook wins over the tokens CSS, without !important. Only a rule with !important in Theme › Custom CSS or in a component style's own CSS takes precedence.
How component CSS is scoped
The CSS in Code › CSS applies to the component only. When BunStack compiles the theme, it puts the component's root in front of every selector. That also applies inside @media, @supports, @container and @layer.
| You write | The storefront gets |
|---|---|
nav a { … } | [data-bs-header] nav a { … } |
[data-bs-header] nav a { … } | Unchanged. The root is already there |
& { padding: 32px; } or [data-bs-header] { … } | The rule for the root itself |
:hover { … } | [data-bs-header]:hover { … } |
[data-bs-transparent]:not([data-bs-scrolled]) svg { … } | [data-bs-header][data-bs-transparent]:not([data-bs-scrolled]) svg { … }. A state on the root is joined to the root |
:root { … }, html { … }, body { … } | Unchanged, with a warning. The rules reach the whole page |
@keyframes, @font-face | Unchanged. src in @font-face should point to a file in the media library |
@import …; | Removed |
[data-bs-transparent]:not([data-bs-scrolled]) svg { stroke-width: 1.4; }
CSS sanitising
BunStack sanitises all CSS: in components, sections, pages and the theme.
- It removes
<, so no</style>can form. - It removes
@import,expression(),javascript:and other script routes. - It keeps
>, so child combinators such as[data-bs-menu] > awork. It also keeps::beforeand::after. - It keeps
!important. The component's CSS comes after the tokens CSS, the style and Theme › Custom CSS, so a plain rule on a hook is usually enough.
BunStack removes CSS it cannot read and shows a warning that names it. The warning shows in the designer and as <!-- bs-component-warning: … --> in the storefront's HTML.
- It removes a rule that never closes.
- It removes text that is not CSS on its own and never joins it to the next rule.
- A selector that continues on the next line needs a comma or a combinator at the line break. Otherwise the first line counts as a note, and BunStack removes it.
The rest of the CSS works.
Fonts
- Upload the font as
.woff2or.woffin the media library. - Press Copy URL on the file.
- Point
@font-face { src: url(…) }at the address.
The storefront's policy loads fonts only from the media library. A font from another address loads neither in the storefront nor on the canvas.
Variables from the theme
Take colours, fonts and radii from the theme's variables. Then they change with the theme:
| Variable | Value |
|---|---|
var(--bunstack-color-primary) | The primary colour |
var(--bunstack-color-fg) | The text colour |
var(--bunstack-font-heading) | The heading font |
var(--bs-surface) | The surface colour for cards and plates |
var(--bs-radius-lg) | The photo corners |
var(--bunstack-button-radius) | The button corners |