Nasaq
Components

Theme presets

Named themes (light or dark plus brand colours): Nasaq, purple, rose and emerald, each dark and light. A picker with live previews, useThemePreset to apply and remember the choice, overrides for tenant colours, and ThemePresetScope to preview a region.

PreviewOpen ↗

Code

function AppearanceSettings({ tenantBrand }: { tenantBrand?: string }) {  const { value, setValue } = useThemePreset({ overrides: { brand: tenantBrand } });  return <ThemePresetPicker value={value} onValueChange={setValue} overrides={{ brand: tenantBrand }} />;}

Brand · beta

Live examples and controls: Theme presets in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/theme-presets.json

A set of named themes the reader can choose from, each a light or dark mode plus brand colours. The picker is a ThemeGallery with previews; useThemePreset applies the choice to the app, remembers it, and layers any overrides (such as a tenant's colour) on top.

When to use

  • An appearance setting with more than light and dark: "Purple", "Rose light".
  • Products that ship a few colour themes over one brand manifest.

When not to use

  • Only light, dark and system: use ThemeToggle from Switchers.
  • Colours from a database for a white-label tenant, with no choice for the reader: use BrandingProvider.

Import

import { ThemePresetPicker, useThemePreset } from "@fadymondy/nasaq/web";

Quick start

function AppearanceSettings({ tenantBrand }: { tenantBrand?: string }) {
  const { value, setValue } = useThemePreset({ overrides: { brand: tenantBrand } });
  return <ThemePresetPicker value={value} onValueChange={setValue} overrides={{ brand: tenantBrand }} />;
}

Anatomy

ThemePresetPicker     a ThemeGallery (data-slot="theme-gallery"), one radio card per preset
ThemePresetScope      data-slot="theme-preset-scope" data-theme=mode
└─ region             data-brand="runtime", the preset's variables inline

API

ThemePreset

{ id, label, labelAr?, mode: "light" | "dark", brand?, brandDark?, accent? }. Without colours a preset keeps the active brand manifest (the built-in nasaq and nasaq-light).

ThemePresetPicker

All ThemeGallery props except themes (value, defaultValue, onValueChange, label, columns, disabled, name, labels, className), plus:

PropTypeDefaultDescription
presets?readonly ThemePreset[]THEME_PRESETSThe choices.
overrides?ThemeOverridesnone{ brand?, brandDark?, accent? }, shown in every preview.

useThemePreset(options)

OptionDefaultDescription
presetsTHEME_PRESETS
defaultValuefirst presetUsed when nothing is stored.
storageKey"nasaq-theme-preset"null turns persistence off.
overridesnoneColours over the chosen preset.
applytrueWrites the variables on <html> and calls NasaqProvider's setTheme(preset.mode).

Returns { value, preset, setValue, presets }.

Helpers

  • applyThemePreset(root, preset, overrides) writes the variables on any element and returns a cleanup.
  • themePresetVars(preset, overrides) returns --nq-brand-l/-d, --nq-action-l/-d, --nq-on-action-l/-d and --nq-accent-brand. Invalid colours are dropped, so a bad stored value falls back to the manifest.
  • ThemePresetScope renders children in a preset without touching the page.

Accessibility

  • The picker is a radio group with arrow-key navigation; each card is named by its label, and the sun or moon icon is decorative.
  • Text on the action colour is ink or ivory, whichever has more contrast.

RTL & i18n

Arabic labels come from labelAr when the locale is Arabic. Previews mirror with the layout.

Styling & tokens

Presets set only the brand variables; every other role (surfaces, text, borders) comes from the light or dark token set, so all presets keep Nasaq's contrast.

Do / Don't

  • Do keep the same family in light and dark so a reader can switch mode without losing their colour.
  • Don't define surfaces or text colours in a preset; let the mode supply them.

Lab

https://docs.nasaqui.com/?path=/docs/components-brand-theme-presets--docs

On this page