Branding
Give the Storefront App your brand from one typed file — colors for light and dark, fonts, buttons, cards, tabs and home screen — plus your app icon and launch screen.
Branding
Everything about how a build looks lives in one typed, validated file, brand/storefront.brand.ts, with the brand's fonts, translations and artwork beside it in brand/. The app's own code stays untouched, so a branded build takes each new release as a plain merge. See Client Builds for the brand/ folder.




The brand file
// brand/storefront.brand.ts
import { defineBranding } from '../src/branding/define';
const body = { family: 'Golos Text', faces: { '400': 'GolosText-Regular', '600': 'GolosText-SemiBold', '700': 'GolosText-Bold' } } as const;
export default defineBranding({
schemaVersion: 1,
name: 'My Store',
colors: {
preset: 'orange',
dark: { background: '#15171B', surface: '#1D2026', primary: '#F5821F', primaryText: '#15171B' },
light: { background: '#F7F4EE', surface: '#EFEAE0', primary: '#C2410C', primaryText: '#FFFFFF' },
extra: {
dark: { gradientStart: '#E8482B', gradientEnd: '#F5821F' },
light: { gradientStart: '#B8360F', gradientEnd: '#C2410C' },
},
},
appearance: { defaultScheme: 'dark', allowUserToggle: true },
typography: { body, heading: body },
shape: { radius: { tile: 14, card: 16, sheet: 22 } },
components: {
productCard: { variant: 'outlined' },
button: { fill: 'gradient', radius: 12 },
chip: { selected: 'filled' },
tabBar: { activeColor: 'primary' },
},
boot: { background: ['#15171B'] },
navigation: { home: 'store', languageSwitcher: true },
});Your editor checks it as you type: defineBranding is typed, and every value is validated when the app starts.
Options
Colors
| Field | Values |
|---|---|
colors.preset | blue, red, green, indigo, orange, truevegan: the starting palette |
colors.light, colors.dark | Overrides for the semantic colors: background, surface, color, textPrimary, textSecondary, textPlaceholder, primary, primaryBorder, primaryText, secondary, secondaryBorder, borderColor, borderColorWithShadow, shadowColor, borderActive, and success, error, warning, info with their …Border and …Text variants |
colors.extra.all, .light, .dark | More theme keys: gradientStart and gradientEnd for gradient buttons, surface2, or your own (e.g. custom, customBorder, customText for a custom tab bar) |
Colors are hex (#rgb, #rrggbb, #rrggbbaa), rgb()/rgba(), white, black or transparent. Text and background pairs are checked against WCAG AA (4.5:1 for body text, 3:1 for secondary text); a pair that fails is reported while you develop.
Appearance
| Field | Values |
|---|---|
appearance.defaultScheme | system (default, follows the device), light or dark |
appearance.allowUserToggle | true (default) lets customers choose system, light or dark in their account |
Typography
| Field | Values |
|---|---|
typography.body, typography.heading | { family, faces }: the family name and, per weight ('100'–'900'), the PostScript name of a font file in brand/fonts. heading defaults to body |
typography.scale | 0.85–1.3 (default 1): scales every text style |
Components and shape
| Field | Values |
|---|---|
components.productCard.variant | bordered (default), outlined or visio (image-led, name and price over the photo) |
components.storeCategories.display | grid (default) or pills on the store page |
components.storeHeader | showGradient, showLocationPicker, showTitle, showDescription, showLogo, logoHeight, logoWidth, direction, alignItems, justifyContent, spacing, paddingTop/Bottom/Left/Right |
components.button.fill | solid (default) or gradient: main buttons filled from gradientStart to gradientEnd |
components.button.radius | 0–32 (default 12) |
components.chip.selected | tinted (default) or filled |
components.tabBar.activeColor | The theme key of the active tab, e.g. primary |
shape.radius.tile, .card, .sheet | Corner radii of tiles (12), cards (16) and sheets (24) |
Images and boot screen
| Field | Values |
|---|---|
assets.loginBackground, assets.bootBackground | { bundled: 'storefront_photo_1' }, { url: 'https://…' } or null |
boot.background | 1–4 colors (or $tokens) behind the boot screen; more than one makes a gradient |
Navigation and screens
| Field | Values |
|---|---|
navigation.home | store (default) or foodTrucks |
navigation.store.tabs, .defaultTab, .tabBar.background | A single store's tabs, its first tab, and blur or a theme key for the tab bar |
navigation.network.tabs, .mainStoreTag, .foodTrucks | A Network's tabs, the tag of its main store, and the Trucks tab |
navigation.foodTrucksView | map (default) or list |
navigation.tabs.<Tab> | { icon, label } for one tab |
navigation.languageSwitcher | true (default) shows a language button in screen headers when more than one language is offered |
screens.<screen id>.variant | A built-in alternative of a screen, e.g. { 'network.home': { variant: 'shop' } } |
What each home screen and tab does: Home Screens & Tabs.
Fonts
Put the font files in brand/fonts, each named after its PostScript name: GolosText-Regular.ttf, GolosText-Bold.ttf (.ttf, .otf, .woff, .woff2).
Declare them under typography in the brand file, as in the example above.
Link them into the native projects with npx react-native-asset, then rebuild. The web build loads them on its own.
Every text style uses the body font; titles and headings use the heading font. A declared face missing from brand/fonts falls back to the system font.
App icon and launch screen
Put your artwork in brand/:
| File | What it is |
|---|---|
brand/app-icon.png | 1024×1024, no transparency (iOS rejects icons with an alpha channel) |
brand/splash-screen.png | The logo on the launch screen; a white or single-color logo on a transparent background works best |
Then generate every size for iOS and Android:
yarn generate:app-icon
yarn generate:launch-screenThe launch screen's background is the brand file's boot.background, or pass --background=#hex. The in-app boot screen that follows shows the same brand/splash-screen.png, so the two match. Without a brand/ artwork file, the templates in assets/ are used.
Copy
brand/translations/<locale>.json is merged over the app's own strings. Change any of them, or add keys for your own tab labels and screens:
{ "Shop": { "searchPlaceholder": "Search rice, flour, oil…" } }A file for a language the app doesn't ship adds that language; offer it with AVAILABLE_LOCALES.
How the brand is resolved
Branding is built from these sources, each overriding the one before:
- The app's defaults.
- Older
.envbranding keys, so existing builds keep their look. brand/storefront.brand.ts, or the empty template at the repository root when a build has none.- A local preview (debug builds only, below).
Each value is validated on its own: an invalid one is dropped and the next source's value is used, so one bad color never discards the rest. A file with an unsupported schemaVersion is ignored.
Previewing colors
In a debug build, store a branding config under storefront:branding-preview and restart to try colors without rebuilding. On the web:
localStorage.setItem('storefront:branding-preview', JSON.stringify({ schemaVersion: 1, colors: { light: { primary: '#be185d' } } }));
location.reload();Remove the key to go back to the build's branding. Release builds ignore previews.
In your own screens
Screens you add read the brand through useBranding() and style themselves with theme tokens ($primary, $textSecondary) and the app's components (src/ui), so they follow the brand and both appearances without extra work. See Extending.