@lattice-ui/react-systemStable directiondepends on runtime, styleSystem sits one level above @lattice-ui/react-style. Style owns the raw theme and host-prop
helpers. System adds the app-facing layer on top of it. A density system scales spacing, radius
and type globally. Layout primitives (Stack, Row, Grid) drive Roblox layout instances from
theme spacing tokens, and surface tones keep backgrounds and borders consistent.
SystemProvider ties the theme and density together and feeds a density-resolved Theme down
through ThemeProvider.
Import
import { SystemProvider, useSystemTheme } from "@lattice-ui/react-system";import { DensityProvider, useDensity, applyDensity, density } from "@lattice-ui/react-system";import { Stack, Row, Grid } from "@lattice-ui/react-system";import { Surface, surface } from "@lattice-ui/react-system";API reference
SystemProvider
The top-level provider. It owns the raw (base) theme, wraps a DensityProvider, and exposes both through a system context. Density transforms are applied internally and the resolved theme is passed down via @lattice-ui/react-style’s ThemeProvider, so any useTheme consumer below sees the density-scaled theme automatically.
function SystemProvider(props: SystemProviderProps): React.Element;
<SystemProvider defaultTheme={defaultDarkTheme} defaultDensity="comfortable"> {app}</SystemProvider>Theme and density are each independently controllable (theme/defaultTheme,
density/defaultDensity). Writes always target the base theme. The resolved theme derives from
the base theme plus the current density.
| Prop | Type | Description |
|---|---|---|
| theme | Theme | Controlled base theme. When set, SystemProvider does not own theme state. |
| defaultTheme | Theme | Initial base theme for uncontrolled usage. Defaults to defaultLightTheme. |
| onThemeChange | (nextTheme: Theme) => void | Called when the base theme changes. |
| density | DensityToken | Controlled density. "compact", "comfortable", or "spacious". |
| defaultDensity | DensityToken | Initial density for uncontrolled usage. Defaults to "comfortable". |
| onDensityChange | (next: DensityToken) => void | Called when density changes. |
| children | React.ReactNode | The subtree governed by this system. |
useSystemTheme
function useSystemTheme(): SystemThemeContextValue;
const { theme, baseTheme, density, setBaseTheme, setDensity } = useSystemTheme();Returns the system context: the density-resolved theme for reading, the baseTheme before density transforms, the current density, and setters. Writes go through setBaseTheme (raw theme) and setDensity. Must be called under a SystemProvider.
DensityProvider
The density layer used internally by SystemProvider, also usable on its own. It reads the base theme from the surrounding system base-theme context, resolves a density-scaled theme, and republishes it through ThemeProvider. Density is controllable via density/defaultDensity.
function DensityProvider(props: DensityProviderProps): React.Element;
<DensityProvider density="compact">{children}</DensityProvider>| Prop | Type | Description |
|---|---|---|
| density | DensityToken | Controlled density value. |
| defaultDensity | DensityToken | Initial density for uncontrolled usage. Defaults to "comfortable". |
| onDensityChange | (next: DensityToken) => void | Called when density changes. |
| children | React.ReactNode | The subtree receiving the density-resolved theme. |
useDensity
function useDensity(): DensityContextValue;
const { density, setDensity } = useDensity();Returns the current density token and a setDensity setter. Must be called under a DensityProvider (or SystemProvider).
applyDensity
function applyDensity(theme: Theme, token: DensityToken): Theme;
const compact = applyDensity(defaultLightTheme, "compact");Pure theme transformer. Returns a new Theme with space, radius, and typography scaled by the
token’s factors and colors carried through unchanged. Spacing and radius are rounded and clamped
to a non-negative minimum. Text sizes clamp to a minimum of 10. Density does not create layout or
child instances — it only reshapes token values.
density
function density(token: DensityToken): (theme: Theme) => Theme;
const compact = density("compact");const scaled = compact(theme);A curried form of applyDensity — returns a theme transformer bound to a token, convenient where a (theme) => Theme function is expected.
Stack
Vertical-by-default flex layout primitive. Renders a transparent frame with a uilistlayout, mapping align/justify to Roblox alignment enums and resolving gap and padding through theme spacing tokens.
function Stack(props: StackProps): React.Element;
<Stack gap={8} align="center" padding={16}> {children}</Stack>align controls the cross axis and justify the main axis (their effect swaps with direction).
gap and every padding field accept a SpaceToken (resolved through the theme) or a raw pixel
number. autoSize maps to AutomaticSize. sx and any direct host props merge on top of the
transparent base. asChild is not supported and throws if passed.
| Prop | Type | Description |
|---|---|---|
| direction | LayoutDirection | "vertical" (default) or "horizontal". |
| gap | SpaceValue | Spacing between children: a space token or pixel number. Defaults to 0. |
| align | StackAlign | Cross-axis alignment: "start", "center", or "end". Defaults to "start". |
| justify | StackJustify | Main-axis alignment: "start", "center", or "end". Defaults to "start". |
| autoSize | StackAutoSize | boolean | "x" | "y" | "xy". Maps to AutomaticSize; true picks the main axis. |
| padding... | SpaceValue | padding, paddingX/Y, and paddingTop/Right/Bottom/Left, resolved via theme spacing. |
| sx | Sx<StyleProps> | Extra host props, merged over the transparent base. |
| children | React.ReactNode | Laid-out children. |
Row
function Row(props: RowProps): React.Element;
<Row gap={6}>{children}</Row>A Stack with direction fixed to "horizontal". Accepts every StackProps field except direction (RowProps = Omit<StackProps, "direction">).
Grid
Responsive grid primitive backed by a uigridlayout. It measures its own AbsoluteSize and
resolves the column count and cell width on layout changes. It either honors a fixed columns or
fits as many minColumnWidth cells as the container allows.
function Grid(props: GridProps): React.Element;
<Grid minColumnWidth={120} gap={8} cellHeight={48}> {children}</Grid>gap sets both axes. rowGap and columnGap override per axis. All spacing accepts tokens or
pixels. cellHeight defaults to 32. Like Stack, asChild is not supported and throws.
| Prop | Type | Description |
|---|---|---|
| columns | number | Fixed column count. When omitted, columns are derived from minColumnWidth and container width. |
| minColumnWidth | SpaceValue | Minimum cell width used to compute responsive column count. |
| cellHeight | SpaceValue | Height of each cell. Defaults to 32. |
| gap | SpaceValue | Spacing for both axes. Defaults to 0. |
| rowGap | SpaceValue | Vertical spacing override. Defaults to gap. |
| columnGap | SpaceValue | Horizontal spacing override. Defaults to gap. |
| autoSize | StackAutoSize | Maps to AutomaticSize; true resolves to the Y axis. Defaults to false. |
| padding... | SpaceValue | Same padding fields as Stack, resolved via theme spacing. |
| sx | Sx<StyleProps> | Extra host props, merged over the transparent base. |
| children | React.ReactNode | Grid cells. |
Surface
Decorated surface host primitive. Renders a frame styled with the chosen tone and, for non-overlay tones, adds a uicorner and uistroke for rounded corners and a themed border.
function Surface(props: SurfaceProps): React.Element;
<Surface tone="elevated" Size={UDim2.fromOffset(240, 120)}> {children}</Surface>For decorated tones the host BorderSizePixel is forced to 0, since uistroke draws the border.
The overlay tone renders a translucent fill with no decoration. sx and direct host props merge
on top. asChild is not supported and throws.
| Prop | Type | Description |
|---|---|---|
| tone | SurfaceToken | "surface" (default), "elevated", "sunken", or "overlay". |
| sx | Sx<StyleProps> | Extra host props, merged over the tone. |
| children | React.ReactNode | Surface contents. |
surface
function surface<Props>(token: SurfaceToken): Sx<Props>;
const elevatedSx = surface("elevated");Props-only counterpart to the Surface primitive. Returns an Sx value that resolves to background, border color, and border-size host props for the given tone — no child instances (no uicorner/uistroke). Use it when you only want the tone’s host props on an existing element. The overlay tone resolves to a translucent overlay fill with no border.
Types
| Prop | Type | Description |
|---|---|---|
| DensityToken | "compact" | "comfortable" | "spacious" | The three density levels. |
| DensityContextValue | { density; setDensity } | Value returned by useDensity. |
| DensityProviderProps | object | Props for DensityProvider. |
| SystemProviderProps | object | Props for SystemProvider. |
| SystemThemeContextValue | object | theme, baseTheme, density, setBaseTheme, setDensity from useSystemTheme. |
| LayoutDirection | "vertical" | "horizontal" | Stack fill direction. |
| StackAlign | "start" | "center" | "end" | Cross-axis alignment. |
| StackJustify | "start" | "center" | "end" | Main-axis alignment. |
| StackAutoSize | boolean | "x" | "y" | "xy" | AutomaticSize selector. |
| StackPadding | object | The padding/paddingX/paddingTop... field group. |
| SpaceToken | keyof Theme["space"] | A key of the theme spacing scale. |
| SpaceValue | SpaceToken | number | A space token or a raw pixel value. |
| StackProps | object | Props for Stack. |
| RowProps | Omit<StackProps, "direction"> | Props for Row. |
| GridProps | object | Props for Grid. |
| SurfaceToken | "surface" | "elevated" | "sunken" | "overlay" | The four surface tones. |
| SurfaceProps | object | Props for the Surface primitive. |
applyDensity and density only reshape token values — they never create or modify Roblox instance graphs. Spacing and radius are rounded and clamped to non-negative values, and text sizes never drop below 10 so labels stay legible at compact density. Layout itself is produced by Stack, Row, Grid, and Surface reading the resolved tokens.