Chrome stable classes
The class hooks the platform guarantees on brand, cart, user menu, promo, chat, locale banner and card chrome, and how a theme overrides them from its own CSS.
On this page
The platform supplies default parts for the brand, cart, user menu, promo bar, chat, locale banner and product cards. Themes render them through the SDK or through the platform blocks in their header and footer. Restyle these parts through the stable classes below. The classes exist only on the platform's parts, not on markup a theme or merchant writes.
Each class is a bare kebab-case token on the element's className. It carries no styling of its
own and is part of the theme contract: the platform may change the Tailwind utilities around it,
never the token.
The override pattern
Write the rules in your theme's src/styles/theme.css, unlayered, with :where():
:where(.header-brand) {
letter-spacing: 0.08em;
}
:where(.cart-count) {
background: var(--color-surface);
border-color: var(--color-line);
}Two things make this work:
- Unlayered CSS beats Tailwind. The platform's utilities live in
@layer utilities. An unlayered rule wins against every layered one regardless of specificity, so you need neither!importantnor a more specific selector. :where()keeps specificity at 0. Your rule stays the easiest thing in the cascade to override, so a later rule of your own, or a state class on the same element, still wins. Source order becomes the override mechanism.
header-brand sits on the link drawn by Brand and Logo from @poltura/theme-sdk/chrome and
by the logo block. Those also render in most theme footers, so a bare .header-brand rule
reaches the footer logo too. Scope footer-only rules through your own footer class.
The classes
| Class | Surface | Notes |
|---|---|---|
header-brand | brand | the brand link: Brand, Logo and the logo block |
header-brand-mark | brand | square initial badge drawn when the store has no logo |
header-brand-label | brand | the store name drawn when the store has no logo |
cart-button | cart | CartButton trigger <button> (also carries data-cart='header') |
cart-count | cart | item count badge |
cart-button-label | cart | the trigger's text label |
cart-panel | cart | desktop popover and mobile sheet content |
cart-panel-title | cart | panel heading |
user-menu-trigger | user menu | UserMenu (and the account block) trigger <button> |
user-menu-content | user menu | dropdown content root |
user-menu-label | user menu | every label in the menu |
promo-bar | promo bar | PromoBar strip root |
promo-bar-inner | promo bar | centred container |
promo-bar-link | promo bar | the announcement link |
inbox-root | chat widget | fixed-position wrapper (data-poltura-inbox) |
inbox-launcher | chat widget | launcher button |
inbox-panel | chat widget | dialog root |
inbox-panel__header | chat widget | title and close row |
inbox-messages | chat widget | scroll region (role="log") |
inbox-message-row | chat widget | wrapper for author, bubble and metadata; --system for system text |
inbox-message | chat widget | actual bubble only; plus --customer, --staff, --ai |
inbox-composer | chat widget | text field, attach and send |
inbox-status | chat widget | offline / reconnecting line |
inbox-offline | chat widget | offline capture form |
locale-banner | locale banner | LocaleBanner suggestion dialog root |
locale-banner-inner | locale banner | padded body |
locale-banner-switch | locale banner | primary "switch language" button |
locale-banner-stay | locale banner | secondary "stay" button |
product-card-body | product card | ProductCard content column |
product-card-title | product card | product title |
product-card-price | product card | price block |
featured-view-all-mobile | product rail | the "view all" link under a ProductRail on small screens |
theme-section-band | built-in sections | a full-bleed band section root |
theme-section-centered | built-in sections | a centred content column inside a section |
The full list of chat widget classes is on Chat widget chrome.
Header states
The header is a section group (layout/header.json), so its pieces are elements that carry the
merchant's own style settings rather than class hooks. Its scroll state is exposed as attributes
for CSS:
| Attribute | On | Meaning |
|---|---|---|
data-theme-chrome='header' | the pinned header box | the promo bar and header together |
data-header-behavior | the pinned header box | static, sticky or reveal |
data-header-overlay | the pinned header box | the header lies over the first section on this page |
data-header-scrolled | the pinned header box | the page has scrolled past the header |
data-header-hidden | the pinned header box | a revealing header is hidden while the shopper scrolls down |
data-header-shrink, -shrunk | the pinned header box | the header shrinks once scrolled, and has shrunk |
data-header-section | the header section root | the header bar |
data-header-mobile-from | the header section root | mobile, tablet or desktop: where the drawer takes over |
:where([data-theme-chrome='header'][data-header-scrolled]) [data-header-section] {
box-shadow: 0 1px 0 var(--border);
}useHeaderVisibility() from @poltura/theme-sdk/chrome reads the same scrolled and hidden
states in code.
Floating elements
Anything a theme pins to the bottom of the viewport (a sticky buy bar, a floating button, its own
banner) adds three offsets to its bottom, each 0px when unset:
| Variable | Set while |
|---|---|
--banner-bottom-offset | a bottom banner bar is showing (its height) |
--preview-bar-offset | the private-preview bar is showing (its height) |
--poltura-editor-inset-bottom | the page is on the Customizer canvas and the Customizer covers its bottom (on phones) |
:where(.my-sticky-buy) {
position: fixed;
bottom: calc(
var(--banner-bottom-offset, 0px) + var(--preview-bar-offset, 0px) +
var(--poltura-editor-inset-bottom, 0px)
);
}The platform's chat launcher, back-to-top button, banners and cookie bar already do this.
--poltura-editor-inset-bottom exists only inside the Customizer, so the live storefront is
unchanged. Without it, an element pinned to the bottom sits under the Customizer's tab bar or
settings sheet on a phone.
What is not hooked
The header's menu, search and language blocks, MainNav, MobileNav, MegaMenu,
MobileMenu, HeaderSearch and LocaleSwitcher carry no class hooks. Style them through the
element's style settings, the className and classes props the SDK parts take (see the
chrome, navigation and
search references), the header attributes above, or their
containers.
Next
- Header mega-menus: wide header dropdowns built from blocks.
- Chat widget chrome: every class and part of the chat widget.