Lattice reference

Style

Theme tokens, recipe and host-prop helpers, and the Box/Text primitives that every styled Lattice UI surface builds on.

@lattice-ui/style Stable direction depends on core

Style is the visual foundation: a theme of design tokens, helpers for merging Roblox host props, a recipe system for variant-driven styling, and the Box/Text primitives that render those props onto host instances. Higher-level packages like @lattice-ui/system and the styled components build directly on it.

The core idea is the sx value — a partial set of host props, or a function from the current Theme to host props. Everything in this package either produces, resolves, or merges sx values, then hands the result to a host instance.

Import

import { Box, Text } from "@lattice-ui/style";
import { ThemeProvider, useTheme, useThemeValue } from "@lattice-ui/style";
import { createTheme, defaultLightTheme, defaultDarkTheme } from "@lattice-ui/style";
import { createRecipe, mergeSx, resolveSx, mergeGuiProps } from "@lattice-ui/style";

API reference

Box

A styled host primitive that renders a frame and applies an sx value resolved against the current theme. Supports asChild to merge its props onto a single child element instead.

function Box(props: BoxProps): React.Element;
<Box sx={(theme) => ({ BackgroundColor3: theme.colors.surface })} Size={UDim2.fromOffset(200, 80)}>
{children}
</Box>

Any host prop passed directly is merged on top of the resolved sx, with direct props winning. When asChild is set, Box requires exactly one valid child element and clones its props onto it (via Slot) instead of rendering a frame.

Prop Type Description
sx Sx<StyleProps> Host props, or a function of the theme returning host props, applied to the frame.
asChild boolean Merge resolved props onto the single child element instead of rendering a frame.
children React.ReactNode Frame children, or the single element to clone when asChild is set.
...rest GuiObject props Any host props, merged on top of sx (direct props win).

Text

Identical to Box, but renders a textlabel instead of a frame. Same sx, asChild, and host-prop merging behavior.

function Text(props: TextProps): React.Element;
<Text
Text="Hello"
sx={(theme) => ({ TextColor3: theme.colors.textPrimary, TextSize: theme.typography.bodyMd.textSize })}
/>
Prop Type Description
sx Sx<StyleProps> Host props, or a function of the theme returning host props, applied to the textlabel.
asChild boolean Merge resolved props onto the single child element instead of rendering a textlabel.
children React.ReactNode Children, or the single element to clone when asChild is set.
...rest GuiObject props Any host props, merged on top of sx (direct props win).

ThemeProvider

Provides the active theme to the tree and exposes a setter. Supports controlled (theme) and uncontrolled (defaultTheme) usage, with onThemeChange notified on every change.

function ThemeProvider(props: ThemeProviderProps): React.Element;
<ThemeProvider defaultTheme={defaultDarkTheme} onThemeChange={handleChange}>
{app}
</ThemeProvider>

When theme is supplied the provider is controlled and setTheme only calls onThemeChange; otherwise it owns the theme internally. Defaults to defaultLightTheme when neither prop is given.

Prop Type Description
theme Theme Controlled theme. When set, ThemeProvider does not own the value.
defaultTheme Theme Initial theme for uncontrolled usage. Defaults to defaultLightTheme.
onThemeChange (nextTheme: Theme) => void Called whenever the theme changes via setTheme.
children React.ReactNode The subtree that should read this theme.

useTheme

function useTheme(): ThemeContextValue;
const { theme, setTheme } = useTheme();

Returns the current ThemeContextValue — the active theme and a setTheme function. Must be called under a ThemeProvider (it uses a strict context and throws otherwise).

useThemeValue

function useThemeValue<T>(selector: (theme: Theme) => T): T;
const accent = useThemeValue((theme) => theme.colors.accent);

Selects and memoizes a derived value from the current theme, recomputing only when the theme or selector changes. Useful for reading a single token without re-running on unrelated context updates.

createTheme

function createTheme(partialTheme?: PartialTheme): Theme;
const brand = createTheme({ colors: { accent: Color3.fromRGB(120, 80, 255) } });

Builds a complete Theme by deep-merging a PartialTheme over defaultLightTheme, group by group (colors, space, radius, typography). Omitted fields fall back to the light defaults.

defaultLightTheme / defaultDarkTheme

const defaultLightTheme: Theme;
const defaultDarkTheme: Theme;

The two built-in themes. Both share the same space, radius, and typography scales and differ only in colors. Use them directly or as the base for createTheme overrides.

createRecipe

A variant-driven styling helper. Given a config of base styles, named variants, default selections, and compound variants, it returns a resolver that turns a variant selection plus a theme into a single merged props object.

function createRecipe<Props, Variants>(
config: RecipeConfig<Props, Variants>,
): (selection: RecipeSelection<Variants> | undefined, theme: Theme) => Partial<Props>;
const button = createRecipe({
base: (theme) => ({ BackgroundColor3: theme.colors.surface }),
variants: {
tone: {
accent: (theme) => ({ BackgroundColor3: theme.colors.accent }),
danger: (theme) => ({ BackgroundColor3: theme.colors.danger }),
},
},
defaultVariants: { tone: "accent" },
});
const props = button({ tone: "danger" }, theme);

Resolution order is base, then each selected variant’s sx (selection merged over defaultVariants), then any matching compoundVariants. Each layer is merged with mergeGuiProps, so later layers win and Event/Change handler tables are composed rather than replaced.

RecipeConfig fields:

Prop Type Description
base Sx<Props> Styles applied before any variant.
variants Record<string, Record<string, Sx<Props>>> Named variant groups mapping each value to an sx.
defaultVariants RecipeSelection<Variants> Selection used when the caller omits a variant.
compoundVariants Array<{ variants; sx }> Extra sx applied when a combination of variant values matches.

mergeSx

function mergeSx<Props>(...sxList: Array<Sx<Props>>): Sx<Props>;
const combined = mergeSx(baseSx, (theme) => ({ TextColor3: theme.colors.textPrimary }), overrideSx);

Combines several sx values into a single theme-resolving function. At resolve time each entry is resolved against the theme and folded together with mergeGuiProps, left to right, so later entries override earlier ones.

resolveSx

function resolveSx<Props>(sx: Sx<Props>, theme: Theme): Partial<Props>;

Resolves a single sx value against a theme: returns it directly if it is a props object, calls it if it is a function, and returns an empty object if it is undefined.

mergeGuiProps

function mergeGuiProps<Props>(
base?: Partial<Props>,
variant?: Partial<Props>,
user?: Partial<Props>,
): Partial<Props>;

The low-level merge used everywhere in this package. It shallow-merges up to three prop objects (base, then variant, then user, last wins) and, crucially, composes the Event and Change handler tables rather than overwriting them — when two layers bind the same event, both handlers run in order.

Types

Prop Type Description
Sx<Props> Partial<Props> | ((theme: Theme) => Partial<Props>) | undefined A static or theme-derived set of host props.
Theme object The full token set: colors, space, radius, typography.
PartialTheme object A deep-partial Theme accepted by createTheme.
ThemeColors object Color tokens: background, surface, surfaceElevated, border, textPrimary, textSecondary, accent, accentContrast, danger, dangerContrast, overlay.
ThemeSpace object Spacing scale keyed by pixel step (0, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 32).
ThemeRadius object Corner radius tokens: none, sm, md, lg, xl, full.
ThemeTypography object Typography styles: labelSm, bodyMd, titleMd.
ThemeTypographyStyle { font: Enum.Font; textSize: number } A single typography entry.
ThemeContextValue { theme: Theme; setTheme: (next: Theme) => void } The value returned by useTheme.
ThemeProviderProps object Props for ThemeProvider.
RecipeConfig object Configuration object passed to createRecipe.
RecipeVariants Record<string, Record<string, Sx<Props>>> The shape of a recipe's variant groups.
RecipeSelection Partial<Record<keyof Variants, string>> A chosen value per variant group.