Storefront CSS styling hooks — reference
For AI tools
Download the CLAUDE.md instruction file and give it to your AI tool (e.g. Claude). It teaches the AI to write safe CSS for your store's Custom Code section only.
A complete catalogue of the stable, semantic CSS class "hooks" on the storefront, so that platform Brand CSS and merchant Vlastný kód can style any component without relying on Tailwind utility classes (which change between builds) or Vue data-v-* scoped attributes (which are build-hashed and unstable).
TL;DR — every meaningful storefront element carries a predictable bare-kebab class. Target it as
.shop-layout .hook-name { … }. You never need!important.
1. Why these exist
The storefront is styled three ways, in this cascade order (later wins):
- Framework — Tailwind v4 utilities + component
<style scoped>blocks. - Brand CSS — platform-owned, SuperAdmin-only, stored in
visual_settings.theme_css, injected inside@layer brand. Beats Tailwind utilities without!important. - Merchant Vlastný kód —
visual_settings.custom_css, injected unlayered, so it beats the brand layer without!important.
The three layers are injected in resources/views/app.blade.php and resources/css/app.css: Brand CSS comes from visual_settings.theme_css (inside @layer brand) and merchant Vlastný kód from visual_settings.custom_css (unlayered, so it wins over the brand layer).
Both Brand CSS and merchant CSS need stable selectors. Tailwind utility classes are not stable (a redesign changes them) and scoped data-v-* hashes change on every build. The hooks in this document are the contract: they don't change, so CSS written against them keeps working.
2. Conventions
- Bare kebab-case, no prefix, no BEM
__. (Matches the pre-existingproduct-title,product-price,language-switcher,category-card.) - Hooks are pure selectors — they carry no styles by default.
- Always scoped by the storefront root:
.shop-layout .hook { … }. - Hooks are added once in a shared component when it only renders in the intended context, otherwise at the per-usage site or per-variant.
- Important boundary: Vue
<style scoped>rules are unlayered, so they outrank@layer brand. Brand CSS can freely restyle utilities, global elements, and anything via CSS variables (--color-primary,--font-headline,--site-max-width, …, which pass straight through the scoped boundary). To recolor/resize inside a scoped component, prefer driving a CSS variable over fighting the scoped rule.
3. How to use — examples
/* Brand CSS (SuperAdmin → Custom Code → Brand CSS tab). Beats utilities, no !important. */
.shop-layout .header-cart { color: #e11d48; }
.shop-layout .product-card { border-radius: 18px; }
.shop-layout .section-title { letter-spacing: -0.02em; text-transform: uppercase; }
/* Merchant Vlastný kód overrides the brand theme, still no !important. */
.shop-layout .header-cart { color: #111; }4. Hook catalogue (by area, with locations)
Legend: Hook = class name · Element = what it sits on · Where = file(s).
Header (all 8 variants)
Variant files: resources/js/Components/Shop/Navigation/Variants/{default,default_static,boutique,large,large_sticky,double_decker,double_decker_static,simple}/Header.vue
| Hook | Element | Where |
|---|---|---|
header-actions | Action-row cluster wrapper | each variant Header.vue |
header-search | Desktop search box | each variant Header.vue (via Search/SearchAutocomplete.vue) |
header-search-toggle | Mobile search button | 7 variants (boutique has an always-visible bar) |
header-menu-toggle | Hamburger button | each variant Header.vue |
header-cart | Cart icon button | resources/js/Components/CartWidget.vue |
header-wishlist | Wishlist icon | resources/js/Components/FavoritesWidget.vue |
header-account | Account icon/link | resources/js/Components/UserAccountWidget.vue |
language-switcher | Language selector | resources/js/Components/LanguageSwitcher.vue (pre-existing) |
currency-selector | Currency selector | resources/js/Components/CurrencySelector.vue (pre-existing) |
Page-builder blueprints
Roots: every resources/js/Components/Shop/Blueprints/*.vue (39 files).
| Hook | Element | Where |
|---|---|---|
<slug>-blueprint | Blueprint outer wrapper | each blueprint, e.g. hero-section-blueprint, product-grid-blueprint, banner-grid-blueprint, faq-section-blueprint, testimonials-section-blueprint, newsletter-blueprint, contact-form-blueprint, card-blueprint, accordion-blueprint, tabs-blueprint, divider-blueprint, image-blueprint, … |
section-title | Blueprint main heading | across Blueprints/*.vue (23 files) |
section-subtitle | Secondary heading / eyebrow | Blueprints/*.vue (15) |
section-text | Body / rich text | Blueprints/*.vue (13) |
section-button | Primary CTA | Blueprints/*.vue (15) |
Product card
Variants: resources/js/Components/Shop/ProductCard/Variants/{default,standart,simple,compact,detailed,large,minimal}/ProductCard.vue
| Hook | Element | Where |
|---|---|---|
product-card | Card root | each ProductCard variant |
product-card-image | Image / thumbnail wrapper | each variant |
product-title | Title heading | each variant (pre-existing) |
product-badge | Label / discount / stock badge | each variant (<ProductLabel>) |
product-price | Price wrapper | Components/Shop/ProductPrice.vue, Components/Products/ProductInfo.vue (pre-existing) |
add-to-cart-btn | Add-to-cart button (main CTA) | Shop/DetailButton.vue, Products/AddToCartButton.vue, Shop/ProductCardHoverOverlay.vue |
product-card-cart-btn | Product-card overlay add-to-cart bubble (round icon button on cards) | Components/Shop/ProductActionButton.vue (when type==='add-to-cart') |
product-listing | Products-grid wrapper | Pages/Shop/ProductListing/Variants/{default,simple,no_banner}/ProductListing.vue |
Product detail
Mostly pre-hooked (product-detail, -info, -gallery-column, -actions, …) in Components/Shop/ProductDetail/Variants/{default,compact}/ProductDetail.vue.
| Hook | Element | Where |
|---|---|---|
product-detail-title | Product name <h1> | Components/Products/ProductInfo.vue |
product-gallery | Image gallery | Components/Products/ProductGallery.vue (+ Variants/default/ProductGallery.vue) |
quantity-input | Quantity stepper | Components/Shop/QuantityInput.vue |
review-list / review-item | Reviews container / a review | Components/Sections/ReviewsCarousel.vue |
Category
| Hook | Element | Where |
|---|---|---|
category-card | Card root | Components/Shop/CategoryCard.vue (root pre-existing) |
category-card-image | Image wrapper | Components/Shop/CategoryCard.vue |
category-card-title | Title | Components/Shop/CategoryCard.vue |
Navigation (non-header), footer, breadcrumb
| Hook | Element | Where |
|---|---|---|
nav-link | Top-level nav link | Components/Shop/Navigation/MenuLink.vue, DesktopMenuItems.vue |
nav-dropdown | Desktop dropdown / megamenu panel | Components/Shop/Navigation/DesktopMenuItems.vue, DropdownMenu.vue |
breadcrumb | Breadcrumb root | Components/Shop/Breadcrumb.vue, Navigation/Variants/simple/Header.vue |
site-footer | Footer root | Navigation/Variants/default/Footer.vue, Navigation/Variants/builder/Footer.vue |
Cart & checkout
| Hook | Element | Where |
|---|---|---|
cart-drawer | Cart drawer panel | Components/Shop/CartDrawer.vue |
cart-item | Cart line row | Components/Shop/CartDrawer.vue, Components/Shop/CartItem.vue |
checkout-form | Checkout form root | Components/Shop/CheckoutForm.vue |
order-summary | Order/cart summary panel | Components/Shop/OrderSummary.vue |
Account area (renders in UserAccountLayout, also .shop-layout)
| Hook | Element | Where |
|---|---|---|
account-nav | Account sidebar/menu | Layouts/UserAccountLayout.vue |
account-nav-link | Account menu link | Layouts/UserAccountLayout.vue |
account-card | Content card/panel | Pages/User/*.vue, Pages/Account/*.vue |
order-detail | Order detail root | Pages/Shop/Orders/Show.vue |
order-line | Order line-item row | Pages/Shop/Orders/Show.vue |
Blog / FAQ / services
| Hook | Element | Where |
|---|---|---|
blog-card | Blog listing item | Components/Shop/BlogCard.vue |
blog-title | Blog card/post title | Components/Shop/BlogCard.vue, Pages/Shop/Blog/Show.vue |
blog-post | Blog article body | Pages/Shop/Blog/Show.vue |
faq-item / faq-question / faq-answer | FAQ entry / question / answer | Components/Shop/FaqAccordion.vue |
service-card | Service listing item | Components/Shop/ServiceCard.vue |
service-detail | Service detail root | Pages/Shop/Services/{Show,ShowBooking}.vue |
Filters, pagination, forms, dialogs
| Hook | Element | Where |
|---|---|---|
product-filter | A filter control | Components/Shop/ProductListingSidebar/Variants/{default,simple,top}.vue |
filter-group | A filter section/group | same as above |
pagination | Pagination control | Components/Shop/Pagination.vue |
form-field | Labelled field wrapper | Components/InputFild.vue, Shop/Filters/CustomInput.vue, auth pages/dialogs |
form-input | Raw <input> / <textarea> | Components/InputFild.vue, Shop/Filters/CustomInput.vue |
form-submit | Primary submit button | auth pages, dialogs, profile sections, PrimaryBtn usages |
shop-dialog | Storefront modal panel | LoginDialog.vue, RegisterDialog.vue, ForgotPasswordDialog.vue, ResetPasswordDialog.vue |
Page roots & titles
Every storefront page carries page-<slug> on its outer wrapper and page-title on its main heading.
| Hook | Page file |
|---|---|
page-title | main <h1>/<h2> on every page (28 files) |
page-cart | Pages/Shop/Cart.vue |
page-checkout / -payment / -confirmation | Pages/Shop/Checkout.vue, Checkout/Payment.vue, Checkout/Confirmation.vue |
page-product | Pages/Shop/Show.vue |
page-product-listing | Pages/Shop/ProductListing/Variants/*/ProductListing.vue |
page-blog-listing / page-blog-post | Pages/Shop/Blog/{Index,Show}.vue |
page-faq | Pages/Shop/Faq/Index.vue |
page-services / page-service-detail | Pages/Shop/Services/{Index,Show,ShowBooking}.vue |
page-order-detail | Pages/Shop/Orders/Show.vue |
page-account-dashboard/-profile/-orders/-addresses/-loyalty/-favorites/-coupons | Pages/User/*.vue, Pages/Account/*.vue |
page-auth-forgot-password/-reset-password/-verify-email/-confirm-password/-complete-profile | Pages/Auth/*.vue, Pages/Account/Auth/CompleteProfile.vue |
page-withdrawal | Pages/Shop/Withdrawal/*.vue |
page-download | Pages/Shop/{DigitalDownload,GiftCardDownload}.vue |
page-error | Pages/Errors/{403,404}.vue |
page-password-protected | Pages/Pages/PasswordProtected.vue |
5. Known gaps & notes
Pages/Pages/Simple.vue(custom builder canvas) has no page-root hook by design — it owns the full canvas and its content is per-blueprint (already hooked).- Header dropdown panels (
nav-dropdown) are teleported and carry.shop-layouton themselves, so a.shop-layout .nav-dropdowndescendant selector won't self-match; target.shop-layout.nav-dropdownor bare.nav-dropdownfor those. - Announcement bar lives inline inside each header variant (already inside the hooked header), so it has no separate root hook.
- Admin (
/admin) is intentionally not hooked — it's Merzio-branded and not merchant-themeable. These hooks are storefront-only. - Shared input wrappers (
InputFild,Filters/CustomInput) also render in a few admin-adjacent profile sections; the.shop-layoutprefix keeps brand/merchant CSS from leaking there.
6. Adding a new hook
- Pick a bare-kebab name; reuse an existing one if the concept matches.
- Prepend it to the element's existing
class="…"(or add a staticclass="…"next to a:classbinding — Vue merges them). Never mutate:class/:style. - Add it once in the shared component if it only renders in one context; otherwise per-usage.
- Record it in this document (area table + location).
npm run build, then verify the class appears in the DOM (document.querySelectorAll('.shop-layout .your-hook')).
Appendix A — Complete hook inventory
This is the full list of stable, semantic hook classes in the storefront, including the many that pre-date the systematic hook effort (they are the components' own <style scoped> class selectors, so they are stable and targetable). Sections 4–5 above are the curated primary set; this appendix is the exhaustive catalogue.
Two kinds of hook — important
- Inert hooks (most of what §4 added:
section-title,product-card,header-*,page-*,account-*, …) carry no CSS by default → both Brand CSS and Vlastný kód style them freely, no!important. - Styled hooks (most items below that live in a component's
<style scoped>:product-detail-*,product-price-*,desktop-sidebar-*,checkout-section-*,card-*, …) already carry the component's own scoped rules (specificity ~0,2,0). To override them: Vlastný kód wins on equal specificity (it's unlayered + injected last); Brand CSS (@layer brand) may need a more specific selector (e.g..shop-layout .product-detail .product-detail-info) or a CSS variable, because unlayered scoped rules outrank a cascade layer. This is the §2 boundary, per-hook.
Root / layout
shop-layout (Layouts/ShopLayout.vue), page-responsive-pad (Pages/Pages/Simple.vue), page-title, and the page-* body-identity family (one per page — see §4 "Page roots").
Header / navigation
header-actions, header-search, header-search-toggle, header-menu-toggle, header-height (all 8 Navigation/Variants/*/Header.vue); header-cart (CartWidget.vue), header-wishlist (FavoritesWidget.vue), header-account (UserAccountWidget.vue), favorite-button-header-icon (Products/FavoriteButton.vue); nav-link, nav-dropdown; nav-link-custom-text / -custom-surface / -custom-hover-text (menu items + several variant headers); breadcrumb, breadcrumb-scroll (Breadcrumb.vue, simple/Header.vue); logo-link, logo-block-container (Blocks/LogoBlock.vue); language-switcher (LanguageSwitcher.vue), language-switcher-block, currency-selector.
Mobile menu
mobile-menu-link, mobile-menu-headline, mobile-menu-subcategory (MobileMenu.vue), mobile-menu-block (MobileMenuBlockRenderer.vue).
Footer
site-footer, footer-grid, footer-row, footer-above, footer-block-above, footer-bottom-bar; footer-builder, footer-column, footer-content-wrapper, footer-row-grid (Variants/builder/Footer.vue); logo-footer / logo-footer-image (LogoFooter.vue — footer logo link + image), merzio-footer-branding (MerzioFooterBranding.vue).
Product card & category
product-card, product-card-image, product-title, product-badge, product-availability-text (ProductCard variants + Products/ProductInfo.vue); category-card, category-card-image, category-card-title (CategoryCard.vue); category-menu-link-styled (CategoryMenuItem.vue).
Product price (family — ProductPrice.vue, ProductInfo.vue)
product-price, product-price-row, product-price-current, product-price-regular, product-price-sale-ends (product-detail wrapper) + sale-end-info (sale end date / live countdown, on cards and detail); Omnibus badge/graph styles: omnibus-badge, price-history-toggle, price-history-chart, price-history-loading, price-history-empty, price-history-canvas (Products/PriceHistoryChart.vue); product-price-unit, product-price-package, product-price-without-vat, product-price-lowest-30d.
Product detail (family — ProductDetail/Variants/{default,compact}/ProductDetail.vue)
product-detail, product-detail-page, product-detail-layout, product-detail-info, product-detail-info-column, product-detail-title, product-detail-description, product-detail-description-title, product-detail-description-content, product-detail-actions, product-detail-stock, product-detail-tags, product-detail-parameters, product-detail-quantity-discount, product-detail-file-upload, product-detail-recommenders, product-detail-thumbnails; gallery: product-detail-gallery, -gallery-column, -gallery-main, -gallery-sticky, product-gallery (Products/ProductGallery.vue); blueprint slots: product-detail-blueprints-above-description, -below-description, -below-cart; share: share-container, share-icon-button, compact-share-button, compact-share-icon; quantity-input (Products/QuantitySelector.vue).
Product listing / filters / sidebar
product-listing, product-listing-banner-section, product-filter, filter-group, product-search-container, product-section, product-slider, product-grid-section, featured-products; range slider (Filters/CustomRangeSlider.vue): custom-range-slider, slider-styled, slider-connect, slider-handle, slider-origin, slider-label, slider-values, number-input, number-input-group, number-input-label, number-inputs; sidebar (ProductListingSidebar*): desktop-sidebar, -nav, -menu, -menu-box, -item, -link, -children, -headline, -text, -toggle, -block, -block-above, -block-below, -banner, -banner-image, -banner-overlay; sort-fade-overlay (ProductListingSorting.vue); pagination (Pagination.vue).
Cart / checkout
cart-drawer, cart-item, cart-added; checkout-form, form-field, form-input, form-radio, form-submit; checkout sections (CheckoutForm.vue): checkout-section-personal-info, -company-info, -billing-address, -delivery-address, -shipping-method, -payment-method, -order-note; order-summary, payment-status (PaymentStatus.vue), free-shipping-info (FreeShippingInfo.vue); add-to-cart-btn, product-card-cart-btn, primary-btn / btn-primary.
Account / auth
account-card, account-nav, account-nav-link (Account pages, Layouts/UserAccountLayout.vue); order-detail, order-line (Shop/Orders/Show.vue); shop-dialog (login/register/forgot/reset dialogs). Page identity classes: the page-account-* / page-auth-* family (§4).
Blog / FAQ / services / reviews
Blog: blog-card, blog-post, blog-title (BlogCard.vue), blog-hero-section, blog-show-hero-section, blog-sort-radio, blog-swiper. FAQ: faq-hero-section, faq-item, faq-question, faq-answer. Services: service-card, service-detail. Reviews (Sections/ReviewsCarousel.vue): review-list, review-item, reviews-swiper, reviews-swiper-prev-btn, reviews-swiper-next-btn.
Blueprints — root identity (Components/Shop/Blueprints/**)
hero-section-blueprint, banner-grid-blueprint, banner-section-blueprint, advanced-banner-blueprint, banner-with-product-blueprint, product-grid-blueprint, category-grid-blueprint, blog-grid-blueprint, newsletter-blueprint, faq-section-blueprint, testimonials-section-blueprint, features-section-blueprint, contact-form-blueprint, contact-info-bar-blueprint, card-blueprint, benefit-card-blueprint, contact-card-blueprint, accordion-blueprint, tabs-blueprint, divider-blueprint, image-block-blueprint, image-carousel-blueprint, layout-section-blueprint, map-embed-blueprint, downloadable-file-blueprint, headline-block-blueprint, button-block-blueprint, product-carousel-blueprint, product-recommender-block-blueprint, blueprint-renderer-blueprint, custom-blueprint, ups-statistics-blueprint, contact-form-{checkbox,select,textarea,text-input,file-upload}-blueprint. Shared per-section hooks: section-title, section-subtitle, section-text, section-button.
Blueprints — inner hooks
- Hero:
hero-carousel,hero-height-custom,hero-swiper-prev-btn,hero-swiper-next-btn,hero-content-padding-responsive. - Banner grid:
banner-grid-swiper,banner-grid-slide,banner-grid-pagination,banner-grid-pagination-dot,banner-grid-custom-height. - Banners:
banner-slider,banner-slide,banner-height,banner-product-swiper. - Grids:
category-swiper,product-swiper,category-grid-section,product-grid-section. - Newsletter:
newsletter-container,newsletter-form,newsletter-header,newsletter-description,newsletter-section. - Divider:
divider-line. Image:image-block,image-block-img,image-placeholder,image-placeholder-builder. - Map embed:
map-embed-container,map-embed-iframe,map-embed-placeholder,map-embed-title,map-embed-builder-badge. - Card / benefit-card / contact-card families:
card-content-container,card-nested-content,card-headline,card-headline-wrapper,card-subtitle,card-subtitle-wrapper,card-text,card-text-wrapper,card-button;benefit-card-icon,-icon-wrapper,-image,-content-container,-nested-content;contact-card-icon,-icon-wrapper,-image,-content-container,-nested-content. - Contact-form inputs:
contact-form-input,contact-form-select,contact-form-textarea,contact-form-checkbox,contact-form-field. - Product recommender:
product-recommender-block,product-recommender-carousel,product-recommender-grid,arrow-button,arrow-icon,pagination-container. - Instagram:
instagram-feed-section,instagram-feed-block.ups-statistics-container.
Nav-builder blocks (Navigation/Variants/builder/Blocks/**)
blueprint-block, contact-info-block, courier-logos-block, courier-logos-container, courier-logo-item, payment-logos-block, payment-logos-container, payment-logo-item, social-links-block, text-block, text-block-container, spacer-block, divider-block, menu-column-block, image-block, logo-block-container, language-switcher-block.
Misc storefront widgets
Flash (StorefrontFlash.vue, BEM): storefront-flash-overlay, storefront-flash-card (+ __icon __text __body __actions __btn __close). AI chat (StorefrontAssistant/ChatWidget.vue, BEM): storefront-ai-chat (+ __header __bubble__user-bubble __chip __input __send __disclaimer). product-assistant-wizard, popup-container, popup-content (PopupDisplay.vue), back-to-top (BackToTopButton.vue), bento-mobile-carousel.
Deliberately excluded (not storefront hooks)
Tailwind utilities; Swiper library internals (swiper-slide, swiper-button-*, swiper-pagination*, swiper-wrapper); Tailwind-plugin classes (prose*, scrollbar-thin, tabular-nums); sr-only / safe-area-* / no-underline utility-ish; state flags (show-popup, success-state, menu-dropdown-open, …); and the admin/Merzio scope (admin-layout, admin-shell-bg, merzio-portal) which is intentionally not merchant-themeable.