BunStackDocs

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.

Last updated · 14 min read

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.

ComponentHookTypeValuesWhat
Header[data-bs-header]rootThe header on every page
Header[data-bs-header-inner]innerThe row inside the header: the page width on Page, out to the side margin on Full
Header[data-bs-logo]innerThe logo link. On a narrow phone it shrinks so the icons and the menu button stay on screen
Header[data-bs-header-nav]innerstart, endThe link row in Logo left and Centered. Split has two halves
Header[data-bs-header-icons]innerThe icon row in the Icons + panel layout
Header[data-bs-menu-button]innerThe button that opens the menu panel
Header[data-bs-cart-icon]innerThe cart icon
Header[data-bs-cart-count]innerThe item count next to the cart icon, kept live
Header[data-bs-wishlist-icon]innerThe wishlist icon
Header[data-bs-announcement]innerThe announcement bar above the header
Header[data-bs-transparent]stateSet on the home page while Transparent over hero is on
Header[data-bs-scrolled]stateSet after 24 px of scrolling, and while the menu panel is open (transparent header only)
Header[data-bs-sticky]stateSet while Sticky is on
Header[data-bs-header-width]statepage, fullThe Width option: page lines the row up with the page content, full runs it out to the side margin
Menu panel[data-bs-menu]rootThe panel that opens from the header
Menu panel[data-bs-menu-layout]innersplit, megaThe panel's grid: Shop + information (split) or Links, products, contact (mega)
Menu panel[data-bs-menu-links]innerThe list of big links
Menu panel[data-bs-menu-link]innerA 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]innerThe list of small links
Menu panel[data-bs-menu-products]innerThe product column beside the links (Links, products, contact)
Menu panel[data-bs-menu-heading]innerThe heading over the products, when one is set
Menu panel[data-bs-menu-cards]innerThe cards. The set changes with the active link
Menu panel[data-bs-menu-contact]innerThe contact bar at the bottom of the panel
Footer[data-bs-footer]rootThe footer on every page
Footer[data-bs-footer-inner]innerThe row inside the footer: the page width on Page, out to the side margin on Full
Footer[data-footer-column]innerbrand, shop, help, legalOne footer column
Footer[data-bs-footer-links]innerThe link list in a column. Where the tokens CSS sets the links' size and opacity
Footer[data-bs-footer-social]innerThe social links in the bottom row. Where the tokens CSS draws their squares
Footer[data-footer-copyright]innerThe copyright line
Footer[data-bs-footer-width]statepage, fullThe Width option, as on Header
Product card[data-bs-card]rootOne product in a grid. Everywhere products are listed
Product card[data-bs-card-media]innerThe photo plate
Product card[data-bs-card-hover]innerThe second photo shown on hover
Product card[data-bs-card-body]innerTitle, tag line and price
Product card[data-bs-card-title]innerThe title
Product card[data-bs-card-meta]innerThe tag line under the title
Product card[data-bs-card-price]innerThe price row
Product card[data-bs-card-variant]statecard, plate, editorialThe card's surface
Product page[data-bs-product-layout]rootclassic, splitThe product page: gallery and buy panel
Product page[data-bs-product-info]innerThe buy panel: title, price, options, add to cart
Product page[data-bs-swatch]innerA colour swatch in the variant picker
Product page[data-bs-cta="primary"]innerAdd to cart and the other primary buttons
Product page[data-bs-image-side]stateleft, rightWhich side the gallery sits on (Split layout)
Gallery[data-bs-gallery]rootThe product images on the product page
Collection page[data-bs-category]rootA collection page: a category, All products or search results
Collection page[data-bs-category-header]innerThe band with the category name
Collection page[data-bs-category-header-inner]innerThe column inside the band
Collection page[data-bs-collection-body]innerThe filters and the grid. From Desktop the sidebar sits beside the grid
Collection page[data-bs-filters-layout]innersidebar, top, noneHow the page lays out the filters
Collection page[data-bs-filters]innerThe filters, in a sidebar or in a row, from Desktop
Collection page[data-bs-filters-mode]innertop, sidebarHow the filters are laid out
Collection page[data-bs-sticky]innerSet 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]innerSet on the row and the bar while they rest under the header
Collection page[data-bs-facet]innerOne filter in the row above the grid: its button and its list
Collection page[data-bs-facet-panel]innerThe list of values that opens under a filter button
Collection page[data-bs-open]innerSet on the filter whose list is open (one at a time), and on an open group
Collection page[data-bs-facet-group]innerOne group in the sidebar and the phone panel: its name and its values
Collection page[data-bs-facet-toggle]innerThe group's name, which folds the group
Collection page[data-bs-facet-body]innerThe part of a group that folds
Collection page[data-bs-facet-values]innerA group's values. Past 240 px they scroll inside the group
Collection page[data-bs-facet-value]innerOne value: its box, its name and its count
Collection page[data-bs-on]innerSet on a ticked value
Collection page[data-bs-count]innerThe count after a value
Collection page[data-bs-clear-filters]innerClear filters (n), at the top of the sidebar
Collection page[data-bs-cta="primary"]innerClear filters in the row; Show N products in the phone panel
Collection page[data-bs-filter-bar]innercountThe 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]innerFilters (n), on phones and tablets
Collection page[data-bs-result-count]innerHow many products the page lists
Collection page[data-bs-sort]innerThe sort control
Collection page[data-bs-filter-panel]innerThe phone and tablet panel, over the page
Collection page[data-bs-filter-sheet]innerThe panel itself, from the left
Collection page[data-bs-filter-shade]innerThe shade behind the panel
Collection page[data-bs-closing]innerSet on the panel while it slides out
Banners[data-bs-banner]rootAn image banner among the page's sections
Banners[data-bs-banner-inner]innerThe copy column over the image
Banners[data-bs-banner-heading]innerThe heading
Banners[data-bs-banner-subtitle]innerThe subtitle
Banners[data-bs-cta]innerprimary, light, outlineThe button
Banners[data-bs-banner-img]innerThe photo of a banner without text. Its height cap follows the screen
Banners[data-bs-banner-size]statexs, sm, md, lg, xl, screenThe height preset on a desktop
Banners[data-bs-banner-size-tablet]statexs, sm, md, lg, xl, screenThe height preset on a tablet: its own, or the desktop one
Banners[data-bs-banner-size-mobile]statexs, sm, md, lg, xl, screenThe height preset on a phone: its own, or the tablet one
Banners[data-bs-bleed]statefull, customFull: the banner runs edge to edge. Custom: a width other than the page

The hooks on the page

HookWhat
[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-padThe content column's vertical gutter, 2.5rem. margin-top: calc(-1 * var(--bs-main-pad)) pulls a section flush under the header
--bs-content-maxThe page width from Theme › Layout, for example 1024px
--bs-gutterThe 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-offsetThe 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 writeThe 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-faceUnchanged. 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] > a work. It also keeps ::before and ::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

  1. Upload the font as .woff2 or .woff in the media library.
  2. Press Copy URL on the file.
  3. 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:

VariableValue
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