Settings

Declare merchant settings in twilight.json and read them in your components.

Read this when you want merchants to change something in your theme without touching code, such as turning the sticky header on, picking an image ratio, or showing breadcrumbs.

Settings are those options. You declare them in twilight.json, and your components read the chosen values.

twilight.json

It sits at the root of the theme. The parts that matter here:

KeyWhat it holds
typeMust be "react" for this engine
name, descriptionTheme name and text, per language
featuresSwitches for dashboard features (for example "fonts", "color", "mega-menu")
settingsThe options merchants can change
componentsThe home page blocks merchants can add

Declare a setting

Each entry in settings has an id (the key you read in code), a type, and a widget format:

twilight.json
{
  "id": "header_is_sticky",
  "label": "Keep the main menu at the top while scrolling",
  "type": "boolean",
  "format": "switch",
  "required": false,
  "value": true
}

The types you will use most:

typeformatValue you read
booleanswitchtrue or false
itemsdropdown-listThe chosen option's value
statictitle, lineNothing: only decoration in the dashboard

A dropdown carries its choices in options, each with a label and a value. Group settings with static entries (a title, a line) so the dashboard stays readable.

Read a setting

useTheme returns the theme's settings. The keys are the ids from twilight.json:

import { useTheme } from '@salla.sa/twilight-theme-engine/hooks/useTheme';

function Header() {
  const { settings } = useTheme();
  const sticky = settings.header_is_sticky !== false;
  // …
}

The starter theme's header reads the same value from useTwilight():

app/components/layout/Header.tsx
import { useTwilight } from '@salla.sa/twilight-theme-engine/providers';

// inside the Header component
const { store, theme } = useTwilight();
const isDefaultLayout = theme?.settings?.header_layout === 'default';
const stickyEnabled = theme?.settings?.header_is_sticky !== false;

Two habits keep this safe:

  • Test for !== false when a setting should be on by default. A store that never saved the setting has no value, and undefined should still mean "on".
  • Check the shape of dropdowns. A value can arrive as a string or as [{ value }], so the starter layout has a small helper that accepts both:
app/components/layout/ThemeLayout.tsx
function productImageRatio(raw: unknown): ImgRatio {
  const first = Array.isArray(raw) ? raw[0] : raw;
  const value =
    typeof first === 'string' ? first : (first as { value?: string } | undefined)?.value;
  return (IMG_RATIOS as readonly string[]).includes(value ?? '') ? (value as ImgRatio) : 'square';
}

Some settings need no code: the engine itself turns footer_is_dark into a body class (see Styling). For the store's own data (name, language options), use useStore and useTheme.

Try settings while developing

While you run the theme locally, the starter shows a small dev-only settings panel. It reads your local twilight.json, fills in the defaults, and lets you flip values live. It handles switches, dropdowns and text. Entries that load their options from the store show as read-only. More in Run locally.

Every key and format is listed in the twilight.json reference.

Next: SEO and head, to control titles and meta tags.

On this page