Theming and customization

Updated: Sep 24, 2026
Customize UI Toolkit for Meta Ray-Ban Display glasses (the toolkit) through its CSS custom properties. Components consume global --uit-* design values through CSS, so overriding a supported semantic token updates every component that uses that role.
The toolkit provides one theme for the additive-light display. It does not provide a light mode, dark mode, or mode switch because the token values target one intended display appearance. Re-point semantic roles instead of swapping entire palettes.
The toolkit does not export a JavaScript theme object. Its theme-related exports are TextAppearance and the TextAppearanceKey and TextAppearanceValue types. Other supported choices are CSS custom properties or closed component enums.

How theming works

App loads the toolkit stylesheet automatically. Override supported semantic tokens in application CSS. Application rules with equal specificity that load after the toolkit stylesheet win through the ordinary CSS cascade.
The stylesheet has four layers:
LayerScopeContents
Design tokens
Document root
Every --uit-* color, spacing, corner-radius, icon-size, opacity, elevation, and component-metric property.
Text appearances
Global classes
The uit-text-* appearance classes.
Secondary foreground utilities
Global classes
uit-color-text-secondary and uit-color-icon-secondary.
Element reset and base styles
The toolkit subtree only
Box sizing, margin and padding reset, the text face, the window background, and primary text color.
App marks its root with data-app-root, and the stylesheet scopes its reset to that element with zero specificity weight. The reset therefore stays within the application and does not override component styles. Tokens remain global so every toolkit component can resolve them, including overlays in the floating portal root.
App registers Noto Sans as the text face. It uses an installed local face without a network request and otherwise loads Noto Sans from the Google Fonts content delivery network at runtime. No font package or additional font configuration is required.

Scope an override

Override on [data-app-root] to theme the whole application:
[data-app-root] {
  --uit-color-text-accent: var(--app-color-accent);
  --uit-color-persistent-action: var(--app-color-action);
}
Override on any ancestor to theme one intentional subtree:
.product-status {
  --uit-color-text-accent: var(--app-color-status-accent);
}
Custom properties inherit, so a subtree override reaches every toolkit component within that element. Prefer application tokens on the right-hand side instead of literal values in component CSS.
Scope overrides to the application root or an intentional subtree. Avoid a :root override that unintentionally repaints host document chrome, and do not target the toolkit implementation details.

Token groups

Text and icon color

--uit-color-text-primary        --uit-color-icon-primary
--uit-color-text-secondary      --uit-color-icon-secondary
--uit-color-text-placeholder    --uit-color-icon-placeholder
--uit-color-text-active-hover   --uit-color-icon-active-hover
--uit-color-text-accent         --uit-color-icon-accent
--uit-color-text-inverse        --uit-color-icon-inverse
Override the semantic role instead of a component’s rendered color:
.status {
  color: var(--uit-color-text-accent);
  background: var(--uit-color-background-elevation1);
}

Background color

--uit-color-background-window          --uit-color-background-flat
--uit-color-background-surface         --uit-color-background-shade
--uit-color-background-elevation1      --uit-color-background-inset
--uit-color-background-elevation2      --uit-color-background-inset2
--uit-color-background-elevation3      --uit-color-background-track
--uit-color-background-backface        --uit-color-background-input-field
--uit-color-background-message-inbound --uit-color-background-input-field-primary
--uit-color-background-message-outbound
--uit-color-background-window is the page role; apply it to html, body, and the mount node. --uit-color-background-elevation3 is a ramp step for component composition, not a standalone surface role, so avoid applying it directly.

Border, interactive, and control

--uit-color-border-primary
--uit-color-interactive-stroke-highlight   --uit-color-interactive-fill-pressed
--uit-color-interactive-stroke-targeted    --uit-color-interactive-text-highlight
--uit-color-interactive-stroke-pressed     --uit-color-interactive-text-edit
--uit-color-interactive-stroke-idle
--uit-color-control-idle
--uit-color-control-active
--uit-color-control-active-background

Button

--uit-color-button-primary-background            --uit-color-button-ai-response-background
--uit-color-button-secondary-background          --uit-color-button-toggle-active-icon
--uit-color-button-primary-targeted-background   --uit-color-button-toggle-active-background
--uit-color-button-primary-targeted-highlight

Persistent status

Persistent roles keep the same meaning wherever they appear, so they are the right place to re-point a status color once:
--uit-color-persistent-action     --uit-color-persistent-caution
--uit-color-persistent-positive   --uit-color-persistent-unread
--uit-color-persistent-warning    --uit-color-persistent-notification
--uit-color-persistent-negative   --uit-color-persistent-recording
--uit-color-persistent-info       --uit-color-persistent-inactive
--uit-color-persistent-active

Accent ramp

--uit-color-accent-red      --uit-color-accent-teal     --uit-color-accent-pink
--uit-color-accent-orange   --uit-color-accent-cyan     --uit-color-accent-rose
--uit-color-accent-yellow   --uit-color-accent-blue     --uit-color-accent-gray
--uit-color-accent-olive    --uit-color-accent-indigo
--uit-color-accent-green    --uit-color-accent-purple
--uit-color-accent-shamrock --uit-color-accent-violet

Loading and container material colors

--uit-color-loading-content
--uit-color-loading-glimmer
--uit-color-container-primary-idle           --uit-color-container-secondary-idle
--uit-color-container-primary-target-step1   --uit-color-container-secondary-target-step1
--uit-color-container-primary-target-step2   --uit-color-container-secondary-target-step2
--uit-color-container-primary-target-step3   --uit-color-container-secondary-target-step3
--uit-color-container-primary-target-step4   --uit-color-container-secondary-target-step4
--uit-color-container-glow
The equivalent inbound and outbound message-container ramps use --uit-color-container-message-inbound-* and --uit-color-container-message-outbound-*, each with four target steps and a glow. These roles feed the default container material’s focus gradient, so an override changes that gradient everywhere. For a different stateful paint on one surface, use ContainerMaterial; see When a material is the right tool.

Spacing

--uit-spacing-2xs      --uit-spacing-xsmall   --uit-spacing-small
--uit-spacing-sm-med   --uit-spacing-medium   --uit-spacing-med-lg
--uit-spacing-large    --uit-spacing-xlarge   --uit-spacing-2xl
--uit-spacing-3xl      --uit-spacing-4xl      --uit-spacing-5xl
Compose an intermediate value with calc() and existing semantic tokens so it continues to respond to theme changes:
.content-inset {
  gap: calc(var(--uit-spacing-large) + var(--uit-spacing-xsmall));
  padding: var(--uit-spacing-large);
}

Corner radius

--uit-corner-radius-xxsmall   --uit-corner-radius-xsmall
--uit-corner-radius-small     --uit-corner-radius-medium
--uit-corner-radius-large     --uit-corner-radius-xlarge
--uit-corner-radius-2xlarge   --uit-corner-radius-3xlarge
--uit-corner-radius-full
Use these fixed tokens in application-authored CSS, but do not redefine them. Toolkit components use the same scale for CSS, SVG, and canvas geometry; choose a public radius enum or shape provider when a component exposes one.

Icon size

--uit-icon-2xs     --uit-icon-xsmall   --uit-icon-small
--uit-icon-medium  --uit-icon-large    --uit-icon-xlarge
--uit-icon-2xl
The toolkit components own their icon-slot sizes. Use these tokens only for icons in application-authored markup.

Opacity and elevation

--uit-enabled-opacity     --uit-elevation-default
--uit-disabled-opacity    --uit-elevation-focused
                          --uit-elevation-pressed
The elevation tokens are box-shadow blur radii, not z-index values.

Header area

--uit-header-area-length
--uit-header-area-length represents the space occupied by a page header. Read it when application CSS must bound a block-axis region, such as reserving space above media. The toolkit components do not consume this token, so overriding it affects only application CSS. For scroll clearance, prefer insetForHeader; scroll components then own the inset, with headerHeight available for a nonstandard header area.
Fading-edge lengths are component metrics rather than header-area tokens. Customize them with the ScrollView props topFadingEdgeLength, bottomFadingEdgeLength, leftFadingEdgeLength, and rightFadingEdgeLength.

Component anatomy variables

The token layer and component stylesheets also declare private variables for component-owned metrics. Some values are written at runtime and can change from frame to frame.
Treat any undocumented --uit-* variable as private. Do not read, override, or reuse it for application layout. This boundary preserves component layout, focus bounds, and compatibility across releases.

Typography

Use the complete typography appearance classes. Each class owns font family, size, line height, weight, and block padding as one contract. The toolkit does not expose piecemeal typography variables or individual metric overrides.
TextAppearance keyClass nameTextStyle value
NUMERAL1
uit-text-numeral1
TextStyle.NUMERAL1
NUMERAL2
uit-text-numeral2
TextStyle.NUMERAL2
DISPLAY1
uit-text-display1
TextStyle.DISPLAY1
HEADING1
uit-text-heading1
TextStyle.HEADING1
HEADING2
uit-text-heading2
TextStyle.HEADING2
BODY1
uit-text-body1
TextStyle.BODY1
BODY1_EMPHASIZED
uit-text-body1-emphasized
TextStyle.BODY1_EMPHASIZED
BODY2
uit-text-body2
TextStyle.BODY2
BODY2_EMPHASIZED
uit-text-body2-emphasized
TextStyle.BODY2_EMPHASIZED
LABEL
uit-text-label
TextStyle.LABEL
LABEL_EMPHASIZED
uit-text-label-emphasized
TextStyle.LABEL_EMPHASIZED
META1
uit-text-meta1
TextStyle.META1
META1_EMPHASIZED
uit-text-meta1-emphasized
TextStyle.META1_EMPHASIZED
META2
uit-text-meta2
TextStyle.META2
META2_EMPHASIZED
uit-text-meta2-emphasized
TextStyle.META2_EMPHASIZED
META3
uit-text-meta3
TextStyle.META3
Prefer TextView, which applies the appearance and the color role together:
import { TextColor, TextStyle, TextView } from '@wearables-ui-toolkit/mrbd';

<TextView as="p" textStyle={TextStyle.META2} textColor={TextColor.SECONDARY}>
  Supporting details
</TextView>
For an application-authored element, use the TextAppearance constant from TypeScript:
import { TextAppearance } from '@wearables-ui-toolkit/mrbd';

<figcaption className={TextAppearance.META2}>Source</figcaption>
CSS and HTML consumers apply the class name directly:
<p class="uit-text-meta2">Secondary details</p>
Both forms resolve to the same class. Prefer body, label, and metadata sizes for routine content. Reserve heading, display, and numeral appearances for the one element that needs that emphasis.

Secondary foregrounds

Apply both the color role and the lighten blend to secondary text and icons. Together they keep a dimmed foreground legible over material on the additive-light display. A color custom property supplies only one declaration, so use the utility classes to apply both behaviors:
<p className="uit-text-meta2 uit-color-text-secondary">Supporting details</p>
<svg className="uit-color-icon-secondary" aria-hidden="true">…</svg>
uit-color-text-secondary resolves --uit-color-text-secondary, and uit-color-icon-secondary resolves --uit-color-icon-secondary; each utility also applies the required compositing. The blend is rendering behavior rather than a customizable semantic token. SVG content must use currentColor to receive the icon color. Because mix-blend-mode does not inherit, place the utility on the element that paints the foreground or on a wrapper whose entire rendered subtree should blend. Do not apply the icon utility to an untinted, full-color image.
Inside the toolkit components, pick the secondary case of the component’s own enum — TextColor.SECONDARY, SubtitleTextColor.SECONDARY, TimestampTextColor.SECONDARY, or IconTintColor.SECONDARY — and let the component apply both parts.

Semantic enums

Component color and shape choices are closed enums, not free-form CSS strings. This is deliberate: a caller picks a role, and the theme decides the value.
ExportWhere it applies
TextStyle, TextColor
TextView
SubtitleTextColor
ListItem subtitles
TimestampTextColor
ListItem timestamps
IconTintColor
Icon slots on Button, ListItem, Modal, and related components
BackgroundStyle
StaticContainer
SurfaceCornerRadius
Surface
ShimmerItemCornerRadius
ShimmerItem
CornerRadius
Shape providers and custom materials
These helpers let application markup resolve the same values as a component:
import {
  IconTintColor,
  getIconTintBlendMode,
  getIconTintCSSVariable,
} from '@wearables-ui-toolkit/mrbd';

const tint = IconTintColor.NEGATIVE;
const glyphStyle = {
  color: getIconTintCSSVariable(tint),
  mixBlendMode: getIconTintBlendMode(tint),
};
getTimestampTextCSSVariable and getTimestampTextBlendMode provide the same behavior for TimestampTextColor. Each blend helper returns a value only for the secondary case and undefined otherwise, ready to spread into a style object.

Customization boundaries

Overrides can re-point supported semantic roles: text, icon, background, border, interactive, control, button, persistent, accent, loading, and container-material colors, plus spacing, corner radii, icon sizes, opacity, and elevation.
Overrides must not:
  • change component anatomy, intrinsic size, or focus bounds;
  • change navigation behavior or accessibility semantics;
  • target private selectors, generated module class names, rendered tags, roles, ARIA or data attributes, or descendants of a toolkit component;
  • use a component-anatomy variable to lay out application content;
  • replace the window background role or make the toolkit root transparent. Use Panel, StaticContainer, Surface, or a card scrim when content needs a legibility surface.
These restrictions protect focus geometry, accessibility, and the public release boundary. If public props and semantic tokens cannot express a design, compose a different component instead of restyling or reimplementing internals.

When a material is the right tool

A token override changes a semantic role everywhere that role appears. For a surface-specific stateful paint—its transitions among idle, targeted, and pressed—use a material instead.
Pass ContainerMaterial to a material host: Container for an interactive surface, StaticContainer for a non-interactive surface, or a higher-level component with a material prop such as Button, ListItem, or Card. Start with a MaterialLibrary factory before authoring layers, and memoize the instance so its one mounted host retains a long-lived material:
import { useMemo, type ReactNode } from 'react';
import { Container, MaterialLibrary } from '@wearables-ui-toolkit/mrbd';
import { appTheme } from './appTheme';

function StatusSurface({ children }: { children: ReactNode }) {
  const material = useMemo(
    () => MaterialLibrary.themedPrimary({
      idleFill: appTheme.surface.idleFill,
      gradientStep1: appTheme.surface.focusCore,
      gradientStep2: appTheme.surface.focusMidpoint,
      gradientStep3: appTheme.surface.focusFalloff,
      gradientStep4: appTheme.surface.focusExtent,
      glowTint: appTheme.surface.glowTint,
    }),
    [],
  );

  return <Container material={material}>{children}</Container>;
}
Token overrides and materials solve different problems. Customize an existing component through supported roles and materials rather than its layer internals.

Motion values

Motion is not part of the CSS token theme. Use the exported AnimationDurations, Interpolators, and SpringConfigs, and build transitions with createTransition so the toolkit motion remains consistent. Reduced-motion preferences must be honored with usePrefersReducedMotion or reducedMotionDuration. Avoid raw durations and cubic-bezier strings.

Validation checklist

Validate every reachable state after a theme change: idle, targeted, pressed, disabled, selected, partial focus, and loading, plus route transitions and focus handoffs used by the screen. A color that works at idle can lose legibility when the focused or pressed material gradient and glow become dominant.
Check the interface on the device and in desktop Chrome during local development.