Latticereference

System

Density scaling, layout primitives, and surface tones layered on top of the style foundation, wired together by a single SystemProvider.

@lattice-ui/react-systemStable directiondepends on runtime, style

System sits one level above @lattice-ui/react-style. Where Style owns the raw theme and host-prop helpers, System adds the app-facing layer: a density system that scales spacing, radius, and type globally; layout primitives (Stack, Row, Grid) that drive Roblox layout instances from theme spacing tokens; and surface tones for consistent backgrounds and borders. 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 is derived from base theme plus current density.

PropTypeDescription
themeThemeControlled base theme. When set, SystemProvider does not own theme state.
defaultThemeThemeInitial base theme for uncontrolled usage. Defaults to defaultLightTheme.
onThemeChange(nextTheme: Theme) => voidCalled when the base theme changes.
densityDensityTokenControlled density. "compact", "comfortable", or "spacious".
defaultDensityDensityTokenInitial density for uncontrolled usage. Defaults to "comfortable".
onDensityChange(next: DensityToken) => voidCalled when density changes.
childrenReact.ReactNodeThe 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>
PropTypeDescription
densityDensityTokenControlled density value.
defaultDensityDensityTokenInitial density for uncontrolled usage. Defaults to "comfortable".
onDensityChange(next: DensityToken) => voidCalled when density changes.
childrenReact.ReactNodeThe 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 are merged on top of the transparent base. asChild is not supported and throws if passed.

PropTypeDescription
directionLayoutDirection"vertical" (default) or "horizontal".
gapSpaceValueSpacing between children: a space token or pixel number. Defaults to 0.
alignStackAlignCross-axis alignment: "start", "center", or "end". Defaults to "start".
justifyStackJustifyMain-axis alignment: "start", "center", or "end". Defaults to "start".
autoSizeStackAutoSizeboolean | "x" | "y" | "xy". Maps to AutomaticSize; true picks the main axis.
padding...SpaceValuepadding, paddingX/Y, and paddingTop/Right/Bottom/Left, resolved via theme spacing.
sxSx<StyleProps>Extra host props, merged over the transparent base.
childrenReact.ReactNodeLaid-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 — either honoring a fixed columns or fitting 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/columnGap override per axis. All spacing accepts tokens or pixels. cellHeight defaults to 32. Like Stack, asChild is not supported and throws.

PropTypeDescription
columnsnumberFixed column count. When omitted, columns are derived from minColumnWidth and container width.
minColumnWidthSpaceValueMinimum cell width used to compute responsive column count.
cellHeightSpaceValueHeight of each cell. Defaults to 32.
gapSpaceValueSpacing for both axes. Defaults to 0.
rowGapSpaceValueVertical spacing override. Defaults to gap.
columnGapSpaceValueHorizontal spacing override. Defaults to gap.
autoSizeStackAutoSizeMaps to AutomaticSize; true resolves to the Y axis. Defaults to false.
padding...SpaceValueSame padding fields as Stack, resolved via theme spacing.
sxSx<StyleProps>Extra host props, merged over the transparent base.
childrenReact.ReactNodeGrid 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 the border is drawn by uistroke; the overlay tone renders a translucent fill with no decoration. sx and direct host props merge on top. asChild is not supported and throws.

PropTypeDescription
toneSurfaceToken"surface" (default), "elevated", "sunken", or "overlay".
sxSx<StyleProps>Extra host props, merged over the tone.
childrenReact.ReactNodeSurface 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

PropTypeDescription
DensityToken"compact" | "comfortable" | "spacious"The three density levels.
DensityContextValue{ density; setDensity }Value returned by useDensity.
DensityProviderPropsobjectProps for DensityProvider.
SystemProviderPropsobjectProps for SystemProvider.
SystemThemeContextValueobjecttheme, 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.
StackAutoSizeboolean | "x" | "y" | "xy"AutomaticSize selector.
StackPaddingobjectThe padding/paddingX/paddingTop... field group.
SpaceTokenkeyof Theme["space"]A key of the theme spacing scale.
SpaceValueSpaceToken | numberA space token or a raw pixel value.
StackPropsobjectProps for Stack.
RowPropsOmit<StackProps, "direction">Props for Row.
GridPropsobjectProps for Grid.
SurfaceToken"surface" | "elevated" | "sunken" | "overlay"The four surface tones.
SurfacePropsobjectProps for the Surface primitive.