From twilight.json to useTheme().settings
Settings you declare in twilight.json become merchant choices, arrive with the store settings, and reach components through useTheme().
A theme is used by many merchants, and each wants it a little different: a sticky header here, a dark footer there. You do not write a version per merchant. You declare the choices in twilight.json, the merchant picks, and your components read the picks.
Step through how a switch in twilight.json becomes a value in your component.
1. You declare the settings
In twilight.json your theme lists the choices a merchant can make: switches, dropdowns, texts. Each has an id, and that id is the name your code reads later.
In engine terms
Each settings[] entry has a semantic type (boolean, items, string, static…) and a widget format (switch, dropdown-list, text…). Booleans and strings keep their default in value, dropdowns in selected or value. static entries are headings and lines for the settings screen and hold no value. The manifest also declares "type": "react".
Both ends of one setting
{
"type": "react",
"settings": [
{
"id": "show_promo_banner",
"type": "boolean",
"format": "switch",
"label": "Show the promo banner",
"value": true
}
]
}
import { useTheme } from '@salla.sa/twilight-theme-engine/hooks/useTheme';
export function PromoBanner() {
const { settings, color } = useTheme();
// Your own id: read it through a cast, and give it the default yourself.
const show = (settings as Record<string, unknown>).show_promo_banner ?? true;
if (!show) return null;
return (
<div style={{ background: color.primary, color: color.reverse_primary }}>
Free delivery over 200 SAR
</div>
);
}
Below, useTheme() runs against the demo store: expand settings to see the merchant's saved values next to the platform ones.
#ed1c24#000000#6e0000font: Dubai · isRTL: true
settings: {…} 26 keys
import { useTheme } from '@salla.sa/twilight-theme-engine/hooks/useTheme';
export function PrimaryButton({ children }: { children: React.ReactNode }) {
const { color } = useTheme();
return (
<button style={{ background: color.primary, color: color.reverse_primary }}>
{children}
</button>
);
}
Why it matters
- It works in development and not on a real store: the dev widget filled in your
twilight.jsondefault, and the real store has no value for it. Give every read a default in code. - A merchant saves a change and the open page does not follow: the theme is kept from the first render. It shows on the next full page load.
- A loader or head function reads a setting through
getTwilightContext().settings.theme.settings: same stored values, but never the dev widget's overrides. - A typo in your own id is not caught by TypeScript (the cast accepts any name). Keep your ids in one constants file.
Go deeper: useTheme, Theme types, DevSettingsWidget, the theme type marker and store settings. Home page blocks are declared in the same file: see Home page blocks.