---
id: "frontend/prism/index"
title: "Overview"
description: "Design system for production React frontends — MUI v9 + Prism."
---

# Prism

<code>@omnitron-dev/prism</code> is the design system. Pre-composed,
theme-aware components and entire UI blocks for building
production React frontends — built on **MUI v9** + **React 19**,
integrated with **react-hook-form + zod**, ready for **Vite /
Next / Remix** out of the box.

```bash
pnpm add @omnitron-dev/prism
```

For React Server Components, put providers and interactive Prism components at
the client boundary. The published UI entry points declare `"use client"`.
Import `@omnitron-dev/prism/http` directly for server-side HTTP calls.

> **React 19 + MUI v9 idioms**
>
> Prism uses the latest patterns from both upstreams:
>
> - **No `forwardRef`** — React 19 routes `ref` through props
>   directly, so every component takes `ref` as a normal prop.
> - **`slotProps` API** — the v9 replacement for the legacy
>   `InputProps={...}` / `MenuProps={...}` / `TabIndicatorProps={...}` /
>   `BackdropProps={...}` / `componentsProps={...}` families.
> - **Unified `<Grid>` with `size={{ xs, sm, md }}`** — v1's
>   `<Grid item xs={...}>` shorthand is gone.
> - **Position classes for grouped controls** —
>   `ToggleButtonGroup` and `ButtonGroup` mark children with
>   `firstButton` / `middleButton` / `lastButton`; theme overrides
>   target those classes instead of the deprecated
>   `:not(:first-of-type)` sibling selector.
>
> See [Components → Refs (React 19)](/docs/frontend/prism/components#refs-react-19)
> and [Components → MUI v9 slot props](/docs/frontend/prism/components#mui-v9-slot-props)
> for the consumer-side migration cheat sheet.

## Three layers of API

```mermaid
flowchart LR
  Blocks[Blocks<br/>full-page composites]
  Layouts[Layouts<br/>shell + slots]
  Components[Components<br/>composable widgets]
  Core[Core primitives<br/>theme, providers, types]

  Blocks --> Layouts
  Blocks --> Components
  Layouts --> Components
  Components --> Core
  Layouts --> Core
```

Pick the level that matches your need:

- [**Blocks**](/docs/frontend/prism/blocks) — copy a `<DashboardBlock>`, fill the
  slots, ship a screen.
- [**Layouts**](/docs/frontend/prism/layouts) — own the routing; use
  `<DashboardLayout>` for shell.
- [**Components**](/docs/frontend/prism/components) — assemble from `<Card>` /
  `<Table>` / `<Drawer>`.
- [**Theme**](/docs/frontend/prism/theme) — palette, typography, shadows,
  density, dark mode.
- [**Forms**](/docs/frontend/prism/forms) — schema-aware forms with `<Field>` +
  `SchemaProvider`.
- [**Hooks catalog**](/docs/frontend/prism/hooks-catalog) — all 48 React hooks.
- [**Maps**](/docs/frontend/prism/maps) — self-hosted MapLibre map, markers,
  point picker and coverage layer.

## Subpath exports

Public subpaths are explicit package exports with matching JavaScript and
TypeScript declarations. For example, `./components/card`, `./components/table`,
`./components/tabs`, `./components/chart` and `./components/map` are available.
A source directory by itself does not create a public import path; there are no
wildcard component exports.

Named imports from the root or `./components` discard unused component modules.
Importing `Card` does not retain the editor, maps or chart engines. Choose a
public subpath when it makes a route's lazy-loading boundary clearer. Editors,
maps, research documents and emoji pickers should load with the routes that use
them.

Import documented `styles.css` entries explicitly for components that need CSS;
these styles remain side-effectful and survive production optimization. Calendar
locale registration stays with its component. CI builds consumers from the real
package archive and verifies both unused dependency removal and preservation of
calendar, map and stylesheet dependencies. Run `pnpm check:packages` after the
workspace build to repeat this check. Measure final application chunks separately:
the size depends on selected components, peers and route boundaries.

| Subpath                                       | What it exports                                                                                              |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `@omnitron-dev/prism`                         | Named imports across the public API; unused modules are discarded                                            |
| `@omnitron-dev/prism/theme`                   | `createPrismTheme()`, palette, typography, shadows, presets                                                  |
| `@omnitron-dev/prism/core`                    | `<PrismProvider>`, `<ProviderStack>`, context primitives                                                     |
| `@omnitron-dev/prism/layouts`                 | `<DashboardLayout>`, `<AuthCenteredLayout>` / `<AuthSplitLayout>` / `<AuthSimpleLayout>`, `<LayoutProvider>` |
| `@omnitron-dev/prism/blocks`                  | `<AuthBlock>`, `<DashboardBlock>`, `<DataGridBlock>`                                                         |
| `@omnitron-dev/prism/components`              | Named imports from the component catalog                                                                     |
| `@omnitron-dev/prism/components/card`         | `Card`, `CardSection`, `StatCard`                                                                            |
| `@omnitron-dev/prism/components/table`        | `Table`, `useTable`                                                                                          |
| `@omnitron-dev/prism/components/map`          | MapLibre map, markers, layers and place search                                                               |
| `@omnitron-dev/prism/components/editor`       | `<Editor>` alone, as its own chunk                                                                           |
| `@omnitron-dev/prism/components/emoji-picker` | `<EmojiPicker>` alone — the dataset is \~80 kB gz                                                            |
| `@omnitron-dev/prism/forms`                   | Schema-aware form helpers                                                                                    |
| `@omnitron-dev/prism/hooks`                   | 48 React hooks                                                                                               |
| `@omnitron-dev/prism/state`                   | Zustand-based store factory                                                                                  |
| `@omnitron-dev/prism/accessibility`           | Vision simulation provider and controls                                                                      |
| `@omnitron-dev/prism/netron`                  | Pre-wired Netron auth/UI bindings                                                                            |
| `@omnitron-dev/prism/http`                    | HTTP fetcher helpers                                                                                         |
| `@omnitron-dev/prism/cli`                     | CLI helpers (used by `prism` bin)                                                                            |

Tree-shaking works on every subpath — import the smallest scope
your bundler needs.

## Minimum wiring

```tsx
import { PrismProvider } from '@omnitron-dev/prism/core';

function App() {
  return (
    <PrismProvider
      defaultSettings={{ mode: 'dark', preset: 'midnight', primaryColor: '#7c4dff' }}
    >
      <Outlet />
    </PrismProvider>
  );
}
```

`<PrismProvider>` builds the theme itself — you do not call
`createPrismTheme()` and hand it over, and there is no `theme`
prop to hand it to. It reads the settings store (persisted, so a
user's own choices survive a reload), falls back to
`defaultSettings` for anything unset, resolves `mode: 'system'`
against the OS preference, and calls `createPrismTheme()` with
the result. The Omnitron console supplies `mode`, `preset` and
`direction` through this settings interface.

`defaultSettings` accepts `mode`, `preset`, `direction`,
`primaryColor`, `contrast`, `fontSize`, `fontFamily` and
`navLayout`. For MUI-level escapes use `themeOverrides`, which is
merged into the generated theme; `config` carries non-theme
configuration. `createPrismTheme()` is exported for building a
theme outside the provider (a standalone MUI tree, a snapshot
test), not for feeding one back in.

Beyond the theme, the provider sets up MUI's `ThemeProvider`,
`CssBaseline`, the snackbar host, the icon registry, and the
localization context (`dateAdapterLocale`, `dateLocaleText`).

For more sophisticated apps, use `<ProviderStack>` to layer
multiple providers cleanly:

```tsx
<ProviderStack
  providers={[
    [QueryClientProvider, { client: queryClient }],
    [AuthProvider,         { client: authClient }],
    [PrismProvider,        { defaultSettings: { mode: 'dark', preset: 'midnight' } }],
    [RouterProvider,       { router }],
  ]}
>
  <Outlet />
</ProviderStack>
```

## State management — `createPrismStore` / `createPersistedStore`

Prism ships Zustand-based store factories (Immer + DevTools +
optional localStorage persistence baked in). Use
`createPrismStore` for general state and `createPersistedStore`
for persisted state with version-aware migration:

```tsx
import { createPrismStore } from '@omnitron-dev/prism/state';

interface UIState {
  sidebarOpen: boolean;
  toggleSidebar: () => void;
}

// Immer middleware is enabled — mutate `state` directly in `set`.
export const useUIStore = createPrismStore<UIState>((set) => ({
  sidebarOpen:   true,
  toggleSidebar: () => set((s) => { s.sidebarOpen = !s.sidebarOpen; }),
}), {
  name:    'ui-store',
  persist: { partialize: (s) => ({ sidebarOpen: s.sidebarOpen }) },
});
```

For persisted preferences with migrations, pass a `version`
plus a `migrate` callback through the persist options:

```tsx
import { createPersistedStore } from '@omnitron-dev/prism/state';

export const useSettings = createPersistedStore<SettingsState>(
  (set) => ({ /* … */ }),
  'settings',                       // store name (positional)
  {
    version: 2,
    migrate: (persisted, version) => {
      // version-aware migration
      return persisted as SettingsState;
    },
  },
);
```

When you bump `version`, persisted state from older versions
runs through `migrate` before being adopted. (See also the
versioned-settings helpers in `@omnitron-dev/prism/state`.)

## Accessibility

`@omnitron-dev/prism/accessibility` exports vision simulation through
`VisionModeProvider`, `useVisionMode`, `VISION_MODE_OPTIONS` and
`getVisionModeStyles`. See [Accessibility](/docs/frontend/prism/accessibility) for
the actual surface and an application-level verification workflow.

## Netron integration — `@omnitron-dev/prism/netron`

Pre-wired auth + UI bindings for apps that talk to a Titan
backend via Netron:

```tsx
import { NetronProvider, createNetronClient }
  from '@omnitron-dev/prism/netron';

const client = createNetronClient({ transport: 'http', url: '/api' });

function App() {
  return (
    <NetronProvider client={client}>
      <Outlet />
    </NetronProvider>
  );
}
```

For multi-backend setups:

```tsx
import { createMultiBackendClient, MultiBackendProvider }
  from '@omnitron-dev/prism/netron';

const client = createMultiBackendClient({
  baseUrl: '',
  backends: {
    main:    { path: '/api/main' },
    storage: { path: '/api/storage' },
    realtime:{ path: '/api/realtime' },
  },
  defaultBackend: 'main',
});

<MultiBackendProvider client={client} autoConnect>
  <Outlet />
</MultiBackendProvider>
```

The bindings re-export `@omnitron-dev/netron-react` hooks —
see [netron/react](/docs/frontend/netron/react) for the full hook
reference.

## CLI — `prism` binary

```bash
prism init                 # scaffold Prism config in current project
prism add card   # generate boilerplate using registered template
prism list --components      # show available components
```

The CLI uses templates from `templates/` (shipped with the
package) plus the schema in `registry.json` for available
component metadata.

## Best practices

- **Pick the smallest layer.** A [`<DashboardBlock>`](/docs/frontend/prism/blocks)
  is faster than composing it from 12 components, but constrains
  you to its prop API. Drop to [`<DashboardLayout>`](/docs/frontend/prism/layouts)
  - components when you need flexibility.
- **One `<PrismProvider>` per app.** Multiple providers create
  duplicate snackbar hosts and confused theme contexts.
- **Use declared entry points.** Consult the [API index](/docs/reference/api-index);
  arbitrary per-component paths are not published.
- **Use schema-driven forms.** [`<Field>` +
  `SchemaProvider`](/docs/frontend/prism/forms) produces consistent UX with zero
  per-field boilerplate.
- **Surface form errors with `<FormAlert>` inline**; reserve
  toasts (`<Snackbar>`) for transient background events.
- **`createPrismStore` / `createPersistedStore` over raw
  Zustand** for any state that persists — the versioned-settings
  helpers handle migrations.

## See also

- [Components catalog](/docs/frontend/prism/components) — 50+ widgets with
  props + examples
- [Blocks](/docs/frontend/prism/blocks) — `<AuthBlock>`, `<DashboardBlock>`,
  `<DataGridBlock>`
- [Layouts](/docs/frontend/prism/layouts) — three app shells
- [Theme](/docs/frontend/prism/theme) — palette, typography, dark mode
- [Forms](/docs/frontend/prism/forms) — schema-aware form patterns
- [Hooks catalog](/docs/frontend/prism/hooks-catalog) — React hooks
- [netron-browser](/docs/frontend/netron/browser) — the RPC client
- [netron-react](/docs/frontend/netron/react) — React hooks for RPC
- [Frontend overview](/docs/frontend/overview) — the three-package picture

## Further guides

- [State and persistence](/docs/frontend/prism/state) — stores, hydration and migrations.
- [HTTP client](/docs/frontend/prism/http) — REST requests, cancellation and interceptors.
- [Component CLI](/docs/frontend/prism/cli) — copy and maintain local component source.
- [API index](/docs/reference/api-index) — every declared public export.