Store View Specific Styling and White Labeling in the Hyva Theme
AI generated
Hyvä
phtml
Hyva Theme, Tailwind CSS, Multi-Brand
Store View Specific Styling
White labeling on a shared codebase

Shipping several brands from a single Hyva codebase sounds simple as long as it is only a different logo. Once color palettes, font sizes, and entire spacing systems need to vary per brand, the choice between CSS variables and separate Tailwind configs decides how maintainable the setup still is a year from now.

11 min read White Labeling Tailwind CSS Multi-Brand

1. Starting point: several brands, one codebase

While Magento's fallback hierarchy and ViewModel based store detection govern which layout content and which translation get delivered per store view, that does not answer a different question: where do the actual design values, such as brand color, accent color, and font size, come from when two brands need to run on the same theme code. This design token layer is exactly what this article focuses on, not the content level store detection itself.

A realistic scenario is an operator running two brands under two store views, each with its own logo, its own color world, and partly its own typography, but an identical product database and identical checkout logic. A full theme fork per brand would be technically possible, but leads to duplicated maintenance on every bug fix or feature change over time.

2. CSS custom properties: Tailwind @theme with var() references

Tailwind CSS v4 in its CSS-first approach defines design tokens directly inside the @theme block as CSS custom properties. Instead of hard coding hex values, the Tailwind variables point at general purpose CSS variables like --brand-primary, whose actual value only gets resolved at runtime in the browser, depending on which store specific CSS file was loaded last.

The big advantage is that a single compiled Tailwind build is enough for every brand, every utility class such as bg-brand-primary stays exactly the same, only the underlying color value differs per store. The downside shows up with deep structural differences, for instance when a brand fundamentally needs larger spacing or a different font family, since steering plain color values through CSS variables is easy, but entire spacing scales are considerably more tedious.


/* web/tailwind/tailwind-source.css */
@theme {
  --color-brand-primary: var(--store-brand-primary, #ea580c);
  --color-brand-accent: var(--store-brand-accent, #fb8570);
}

/* web/css/store-brand-a.css, loaded per store view through layout XML */
:root {
  --store-brand-primary: #0f4c81;
  --store-brand-accent: #7fb2e5;
}

3. Separate Tailwind builds per brand

The alternative is a standalone Tailwind build per brand, each with its own @theme block and its own hard coded color and spacing system, but the same underlying phtml template code. Hyva's hyva.config.json supports several theme directories within the same vendor namespace, so each brand can get its own web/tailwind directory with its own build output.

This approach fits once brands differ not only in color but structurally, for instance different border radius values, entirely different font size scales, or even different grid systems. The price is a separate build process and a separate, shipped CSS file per brand, which makes the deployment workflow more complex than a single, universal CSS file.


{
  "themes": {
    "Mironsoft/brand-a": {
      "css-file": "tailwind/tailwind-source.css"
    },
    "Mironsoft/brand-b": {
      "css-file": "tailwind/tailwind-source.css"
    }
  }
}

4. Trade off: runtime flexibility versus build time optimization

CSS variables are flexible at runtime: a new store with a new accent color only needs a new, small CSS file with the matching custom properties, no new Tailwind build and no new deployment of the compiled base file. That makes this approach ideal for reseller models with many, similarly structured brands, where mostly the color palette differs.

Separate configs, in turn, offer better build time optimization, since Tailwind's purge mechanism includes only the utility classes actually used per brand in the final CSS file, without dragging along unused CSS variable definitions for brands that do not even exist on that instance. With only two or three structurally similar brands, the maintenance advantage of the CSS variable solution usually wins out in practice.

5. How the theme fallback system loads store specific CSS

The store specific CSS file with the custom property overrides is not hard linked in the base template, it is included through its own layout XML handle per store view, such as default_storeview_brand_a.xml, which Magento's fallback hierarchy automatically resolves only for the matching store. That keeps the brand to store view mapping declarative and controllable without code branching in PHP or in the template.

It is important to load the store specific CSS file after the compiled Tailwind base file, so the custom property overrides actually take effect instead of being overwritten by the defaults from the @theme block. The load order inside the head block directly decides whether the white labeling becomes visible at all.


<!-- app/design/frontend/Mironsoft/default/Magento_Theme/layout/default_storeview_brand_a.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <css src="css/store-brand-a.css"/>
    </head>
</page>

6. Asset swapping: logo, favicon, and social images per store view

Besides colors, swapping image assets is at the core of every white labeling setup. Magento's store design configuration already lets you set logo and favicon independently per store view right from the admin area, with no extra theme code needed, as long as the logo template in the theme properly uses $block->getLogoSrc() instead of a hard coded path.

For social media preview images and other meta assets not covered by the standard store design configuration, a dedicated ViewModel that determines the current store and returns the matching asset path from a configuration map is a good fit, rather than maintaining that mapping through scattered conditionals across several templates.

7. Tailwind safelist pitfalls with dynamic brand classes

A common mistake in CSS variable based multi brand styling is assembling class names dynamically from PHP or JavaScript, such as 'bg-brand-' . $brandSlug. Tailwind's purge process only scans templates for complete, static class names and does not recognize such composed strings, so the affected utility class simply ends up missing from the final build.

The reliable fix is to use fully written out class names such as bg-brand-primary exclusively, and to push the actual brand distinction entirely down to the CSS variable level rather than the class name level. That keeps the purge scan reliable, no matter how many brands get added later on.

8. Deployment workflow for several brands at once

With the CSS variable approach, the deploy flow stays unchanged compared to a single brand setup: one Tailwind build, one setup:static-content:deploy call for all stores together, the store specific CSS files with the custom property overrides are lean enough to ship directly without separate build steps.

With separate Tailwind configs per brand, each brand needs its own build run before the actual static content deploy, and the deploy command itself has to be called per theme directory with the matching -t flag. That automates well, but should be deliberately documented in CI scripts, so no build step gets forgotten when a new brand is added.


# Separate configs: build per brand, then a shared deploy
bin/npm --prefix app/design/frontend/Mironsoft/brand-a/web/tailwind run build
bin/npm --prefix app/design/frontend/Mironsoft/brand-b/web/tailwind run build
bin/magento setup:static-content:deploy de_DE -t Mironsoft/brand-a -f
bin/magento setup:static-content:deploy de_DE -t Mironsoft/brand-b -f

9. Long term maintainability: documenting design tokens

The more brands run on the same codebase, the more important a central overview of every available design token becomes, ideally as its own markdown file or a Storybook-like reference page documenting which CSS variable serves which visual purpose. Without that documentation, every new brand invents its own, slightly different variable names, and consistency erodes step by step.

Regression risk mostly arises where a shared template unintentionally contains brand specific assumptions, such as a hard coded color instead of a variable in a rarely tested corner like the error page. A short visual regression check per brand on every theme release, even just as a screenshot comparison, catches such cases more reliably than a purely manual review.

Approach Build effort Runtime flexibility Maintainability Recommended for
CSS custom properties Low, one shared build High, a new brand needs no new build High with similar structure Many, structurally similar brands
Separate Tailwind configs High, one build per brand Low, a change needs a new build Medium, more files to maintain Few brands with structural differences
Full theme fork Very high, independent codebases Very high, completely free Very low, duplicated maintenance on every fix Only for radically different brands
Store design configuration (assets) Low, admin configuration High, changeable instantly in the admin area High, no code changes needed Logo, favicon, and simple asset swaps

Mironsoft

Hyvä theme development and Luma migration

Still running Luma, or a Hyvä theme that just doesn't feel right?

We build Hyvä themes for Magento from scratch or migrate existing Luma shops cleanly, with Tailwind CSS, Alpine.js, and none of the unnecessary JavaScript baggage.

Luma-to-Hyvä Migration

Move an existing shop to Hyvä in a structured way, without losing functionality.

Custom Theme Development

Build a custom Hyvä theme from scratch based on your design.

Performance Optimization

Improve Core Web Vitals and load times in the Hyvä frontend with purpose.

10. Summary

White Labeling in Hyva

CSS variables for color worlds

Tailwind @theme with var() references allows new brands with no new build, as long as mostly colors differ.

Separate configs for structural differences

Once spacing, font sizes, or grids differ fundamentally, a dedicated Tailwind build per brand pays off.

Load order decides whether it works

Store specific CSS must load after the compiled base file, otherwise the custom property overrides never take effect.

Full class names for a safe purge

Dynamically assembled Tailwind class names get missed by the purge scan, brand distinction belongs at the CSS variable level.

11. FAQ: White Labeling in Hyva

1What is the difference between CSS variables and separate Tailwind configs for multi brand setups?
CSS variables allow one shared Tailwind build for every brand, with only the custom property values varying per store. Separate configs build a fully independent Tailwind stylesheet with its own design system for each brand.
2When is a full theme fork worth it instead of varying design tokens?
Only when brands differ heavily not just visually but structurally in layout and feature set. For pure color and typography differences, a fork is almost always unnecessary maintenance overhead.
3How do I load store specific CSS for only one particular store view?
Through a dedicated layout XML handle such as default_storeview_brand_a.xml, which Magento's fallback hierarchy automatically resolves only for the matching store, with no conditionals in PHP code at all.
4Why aren't my CSS variable overrides taking effect?
Usually it is the load order: the store specific CSS file must load after the compiled Tailwind base file, otherwise the defaults from the @theme block overwrite the store specific values.
5Can I assemble Tailwind class names dynamically from PHP, such as bg-brand- plus a brand name?
Not reliably, Tailwind's purge scan only recognizes complete, static class names in templates. Dynamically composed strings cause the utility class to be missing from the final build.
6How do I swap logo and favicon per store view?
Through Magento's store design configuration in the admin area, provided the theme template uses $block->getLogoSrc() instead of a hard coded path, with no extra code needed.
7How does this article differ from an article about fallback hierarchy and store detection?
This article covers the design token layer, meaning where color and spacing values per brand come from. Fallback hierarchy and ViewModel based store detection are a separate topic at the layout and content level.
8Do I need a new Tailwind build for every new brand?
With the CSS variable approach, no, a new, small CSS file with the matching custom properties is enough. With separate Tailwind configs per brand, a dedicated build run is required.
9How do I deploy several brands with separate Tailwind configs at once?
Each brand needs its own build call, followed by its own setup:static-content:deploy call with the matching -t flag for that theme directory.
10How do I prevent regressions when several brands share the same codebase?
A central documentation of every design token, plus a short visual regression check per brand on every theme release, even as a simple screenshot comparison, reliably catches hard coded, brand specific assumptions.