Skip to content

Styling

Rezi styling is:

  • explicit
  • deterministic
  • theme-aware
  • composable through inheritance and scoped overrides

Inline styles

Use inline style props for one-off presentation.

import { resolveColorToken, type ThemeDefinition, ui } from "@rezi-ui/core";

function warningPanel(activeTheme: ThemeDefinition) {
  return ui.box(
    {
      border: "rounded",
      p: 1,
      style: { bg: resolveColorToken(activeTheme, "bg.elevated") },
    },
    [ui.text("Warning", { style: { fg: resolveColorToken(activeTheme, "warning"), bold: true } })],
  );
}

Container style inherits to descendants unless a child overrides it.

Theme-based styling

Themes are semantic ThemeDefinition objects.

import { ui, darkTheme, lightTheme } from "@rezi-ui/core";
import { createNodeApp } from "@rezi-ui/node";

const app = createNodeApp({ initialState: {}, theme: darkTheme });
app.view(() => ui.text("Hello"));

await app.start();

Switching themes at runtime:

app.setTheme(lightTheme);

Design-system defaults

Built-in semantic themes automatically enable recipe styling for core widgets.

  • You do not need dsVariant or dsTone for baseline polished styling.
  • Manual widget styles merge on top of recipe output.
  • app.setTheme(...) and scoped overrides use the same semantic token model.

Validation and extension

Theme hardening APIs:

  • validateTheme(theme)
  • extendTheme(base, overrides)
  • contrastRatio(fg, bg)
import { darkTheme, extendTheme, rgb, validateTheme } from "@rezi-ui/core";

const brandTheme = extendTheme(darkTheme, {
  colors: {
    accent: {
      primary: rgb(255, 180, 84),
    },
  },
  focusIndicator: {
    bold: true,
    underline: false,
  },
});

validateTheme(brandTheme);

Theme colors use packed Rgb24 values, so author them with rgb(...) or color(...), not { r, g, b } objects.

Scoped theme overrides

Use ui.themed(...) for subtree-specific theme changes:

import { rgb, ui } from "@rezi-ui/core";

ui.column({}, [
  ui.text("parent"),
  ui.themed(
    {
      colors: {
        accent: {
          primary: rgb(255, 140, 90),
        },
      },
    },
    [ui.text("scoped")],
  ),
  ui.text("parent restored"),
]);

Scoped overrides:

  • compose predictably
  • inherit unspecified values
  • can override colors, spacing, focusIndicator, and widget palettes

box, row, column, and grid also accept a theme prop for scoped overrides when that is more convenient than wrapping with ui.themed(...).

Dynamic styles

Compute styles from state, but keep view(state) pure.

import { resolveColorToken, type ThemeDefinition, ui } from "@rezi-ui/core";

function connectionStatus(activeTheme: ThemeDefinition, state: { connected: boolean }) {
  return ui.text(state.connected ? "Online" : "Offline", {
    style: {
      fg: resolveColorToken(activeTheme, state.connected ? "success" : "error"),
    },
  });
}