Design systems

Core owns meaning. Your design owns the surface.

TSX
const design = {
  name: 'my-design',
  fields: { text: TextInput, number: NumberInput, boolean: Checkbox },
  groups: { group: { variant: 'basic', Renderer: Group } },
  repeaters: { undereachother: RepeaterStack },
  Form, Loading, Failure,
}

<Tungsten schema={schema} design={design} onSubmit={save} />

Renderer contracts

A field receives its descriptor, runtime state, inputId, required, disabled, readOnly and onValueChange. Render visibility is handled by the host. A design form receives children, onSubmit, submitting, busy and error.

Group renderers receive groupId, children or section descriptors, disabled, errorCount and reveal. Repeater renderers receive ordered stable instance IDs, labels, contents, field keys, limits/availability, reveal and add/remove/reorder callbacks. They own navigation and must reveal an inactive invalid field when requested.

Tokens and installation

The default design scopes styles under tg-root. Override the tg-color-* tokens, tg-radius-control, tg-radius-panel, tg-field-gap and shadow tokens on the rendered root inside a host wrapper. Custom designs should scope their CSS and may provide an install callback for styles.

Light and dark mode

Pass light or dark through colorScheme on a form or editor, or use TungstenThemeProvider for several instances. Omitted choices inherit the provider, otherwise light. Your application resolves system preferences and stores its choice. Theme changes preserve values, errors, focus and editor drafts.

TSX
import { Tungsten, TungstenEditor, TungstenThemeProvider } from '@myoon/tungsten/react'

<TungstenThemeProvider colorScheme={appColorScheme}>
  <Tungsten schema={schema} onSubmit={save} />
  <TungstenEditor initialSchema={schema} />
  <Tungsten schema={anotherSchema} colorScheme="light" />
</TungstenThemeProvider>

Custom designs can read the selected scheme with useTungstenColorScheme(). Override color and shadow tokens on the rendered tg-root or te-root, with separate overrides for each scheme.

Color profiles

Sprout is the only built-in color profile. Its light and dark palettes match this website. Pass colorProfile on a form, editor or TungstenThemeProvider; omitted choices inherit the provider, otherwise sprout.

TSX
<TungstenThemeProvider colorProfile="sprout" colorScheme={appColorScheme}>
  <Tungsten schema={schema} />
  <TungstenEditor initialSchema={schema} />
</TungstenThemeProvider>

// Your custom CSS profile; explicitly selected siblings remain Sprout.
<TungstenThemeProvider colorProfile="ocean" colorScheme={appColorScheme}>
  <Tungsten schema={schema} />
  <TungstenEditor initialSchema={schema} />
  <Tungsten schema={anotherSchema} colorProfile="sprout" />
</TungstenThemeProvider>

Custom profile names select your CSS; they do not generate or load colors. Load overrides after the design stylesheet and target each tg-root and te-root by data-tg-color-profile and data-tg-color-scheme. Unspecified tokens inherit Sprout.

TypeScript
/* Load after Tungsten's design CSS. Unspecified tokens keep Sprout defaults. */
:is(.tg-root, .te-root)[data-tg-color-profile='ocean'] {
  --tg-color-accent: #245ca5;
  --tg-color-accent-deep: #174578;
  --tg-color-accent-soft: #e8f0fc;
  --tg-color-action: #174578;
  --tg-color-action-hover: #11365f;
  --tg-color-on-action: #ffffff;
  --tg-shadow-focus: 0 0 0 3px rgb(36 92 165 / 25%);
  --tg-shadow-button: 0 5px 16px rgb(23 69 120 / 15%);
}

:is(.tg-root, .te-root)[data-tg-color-profile='ocean'][data-tg-color-scheme='dark'] {
  --tg-color-accent: #9ec5ff;
  --tg-color-accent-deep: #9ec5ff;
  --tg-color-accent-soft: #233753;
  --tg-color-action: #9ec5ff;
  --tg-color-action-hover: #bad6ff;
  --tg-color-on-action: #10243e;
  --tg-shadow-focus: 0 0 0 3px rgb(158 197 255 / 30%);
  --tg-shadow-button: 0 5px 16px rgb(0 0 0 / 30%);
}

This example changes accents and actions. Copy the Sprout light/dark token blocks to also customize surfaces, text, state colors and shadows. Editor colors derive from the form tokens. Check contrast and focus in both modes. Bootstrap and Material retain their own palette systems.

Discoverable extensions

Rust field types implement FieldType::descriptor to publish settings as ordinary Tungsten components, validators and operations. Group/repeater libraries provide register_described alongside existing registration. Metadata follows registry order and names; an undescribed extension exposes a JSON settings fallback. The compiler remains the authority.