Skip to content
Twilight React Playground
ثيم رائدaren

From twilight.json to useTheme().settings

Beginner6 min

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.

twilight.jsonsettings[]Merchant savesSalla dashboardStore settingstheme.settingsRoot beforeLoadevery requestTwilightProvidertheme, first renderuseTheme()settings, color, fontYour componentsetting ?? defaulttwilight:schemadev server onlyDev settings widgetoverrides after mount

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

twilight.json (excerpt)
{
  "type": "react",
  "settings": [
    {
      "id": "show_promo_banner",
      "type": "boolean",
      "format": "switch",
      "label": "Show the promo banner",
      "value": true
    }
  ]
}
app/components/PromoBanner.tsx
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.

The merchant's theme colors, font and settings, as the store answers with them.Try this: switch the language pill (top bar, or the ☰ menu on a phone) to en and watch isRTL change.
Storefront canvas · en · LTR
color.primary #ed1c24
color.text #000000
color.reverse_primary #6e0000

font: Dubai · isRTL: false

settings: {…} 26 keys
font: {…} 5 keys
imageZoom: false
show_tags: true
store_color: "#ed1c24"
homepage_type: "custom"
is_custom_css: true
theme_version: "1.188.0"
footer_is_dark: false
topnav_is_dark: false
important_links: true
store_font_type: "default"
enable_more_menu: true
footer_menu_type: "default"
header_is_sticky: true
header_menu_type: "default"
default_font_name: "خط سلة الافتراضي (جديد)"
translations_hash: "1789908891"
sticky_add_to_cart: true
customization_css_ver: 1778680971
is_more_button_enabled: true
slider_background_size: "cover"
vertical_fixed_products: false
enable_add_product_toast: true
squar_photo_bg_image_size: "cover"
is_show_more_detail_enabled: true
is_breadcrumbs_enabled: true
What a theme writes
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.json default, 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.
Check yourself

On a published store, what does the engine do with the value you gave a setting in twilight.json?

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.