Getting started
You’ve built an Arc backend—a RegisterAuthor command and an AllAuthors query—and dotnet build generated typed proxies for both. Components turns those proxies into forms, dialogs, and data views that already know how to validate, execute, and show query results. By the end of this page you’ll click Add author, type a name, and watch the dialog run RegisterAuthor and close on success.
Prerequisites
Section titled “Prerequisites”- A React 19 application built with TypeScript. Components declares
reactandreact-dom^19.0.0as peers. - An Arc frontend with generated proxies and
experimentalDecorators/emitDecoratorMetadataenabled. The Arc tutorial’s first slice sets up the project,tsconfig.json, and Vite proxy that this page assumes. @cratis/arcand@cratis/arc.reactin the range>=20.3.1 <23. This repository builds and tests against Arc 22.16.0; other versions in the range are accepted by the peer declaration but are not all exercised here.
The examples use the proxies from the Arc tutorial: RegisterAuthor has a required id and a name, and AllAuthors is an observable query on the Author read model in ./Authors/Author.
Install and wire it up
Section titled “Install and wire it up”-
Install Components.
Install Components 4 npm install @cratis/components@^4React Aria, the internationalized date implementation, and React Icons are internal dependencies. The package does not depend on PrimeReact or any other UI kit or theme runtime, and you don’t configure an icon package. The optional MUI and PrimeReact integrations are separate renderer adapter packages.
The package requires React, Arc, Fundamentals, and
reflect-metadataas peers.tsyringeis an optional peer: Components never imports it, and Arc React installs it as its own dependency. Keep@cratis/arcand@cratis/arc.reacton the same version your generated proxies were produced with. A strict installer can install the required peers explicitly (replace the Arc version with the one your backend uses):Install explicit peers ARC_VERSION=22.16.0npm install @cratis/components@^4 \"@cratis/arc@$ARC_VERSION" "@cratis/arc.react@$ARC_VERSION" \@cratis/fundamentals@^7.19.2 react@^19 react-dom@^19 \reflect-metadata@0.2.2Use Arc 22.16.0 or newer if you plan to use
AutoCommandForm’s explicit field binding.pixi.js@^8.20.0is another optional peer, needed only if you useCanvasorPivotViewer. Every other component needs nothing beyond the required peers above; install Pixi later, when you reach a spatial workspace or card-grid screen. See Choosing a component. -
Import the stylesheets once, at your application entry point, after
reflect-metadata:src/main.tsx import 'reflect-metadata';import '@cratis/components/tokens';import '@cratis/components/styles';import '@cratis/components/theme'; // optional baseline appearanceimport { createRoot } from 'react-dom/client';import { App } from './App';createRoot(document.getElementById('root')!).render(<App />);tokensdefines stable--cratis-*variables with conservative light defaults.stylessupplies no-Preflight component structure in low-priority Cratis layers.themeadds automatic and explicit dark mode, forced colors, and themed subtrees.A product with its own design system can omit
theme, map its own variables onto--cratis-*, and customize stabledata-cratis-partelements orptattributes.stylesis every component’s CSS in one file. To download only the surfaces you mount, import@cratis/components/styles/baseplus one<subpath>/stylesentry point per surface instead — see Per-area stylesheets.The stylesheet subpaths ship no type declarations. If TypeScript reports
TS2882: Cannot find module or type declarations for side-effect import, declare them once, for example insrc/cratis-components-styles.d.ts:src/cratis-components-styles.d.ts declare module '@cratis/components/tokens';declare module '@cratis/components/styles';declare module '@cratis/components/theme'; -
Mount both providers around your application.
<Arc>supplies the command and query runtime the generated proxies use;CratisComponentsProvidersupplies Components’ locale, labels, and optional toast region. The Components provider does not replace<Arc>:src/App.tsx import { Arc } from '@cratis/arc.react';import { CratisComponentsProvider } from '@cratis/components';import { Library } from './Library';export const App = () => (<Arc><CratisComponentsProvider value={{ locale: 'en-US' }} toaster><Library /></CratisComponentsProvider></Arc>);
Yarn PnP with Arc React 22.6.2
Section titled “Yarn PnP with Arc React 22.6.2”If you retain @cratis/arc.react@22.6.2, that version imports rxjs without declaring it. A strict Yarn PnP consumer needs rxjs@7.8.2 and this version-specific package extension:
packageExtensions: '@cratis/arc.react@22.6.2': dependencies: rxjs: '7.8.2'This workaround is not needed with Arc React 22.16.0. Remove the old extension when upgrading; do not apply it to every Arc version.
What the provider sets up
Section titled “What the provider sets up”CratisComponentsProvider supplies the locale, Components-specific labels, and an optional app-wide toast region (toaster). React Aria uses the locale for date, number, keyboard, and screen-reader behavior. Styling remains CSS-owned rather than provider-owned. Every value is optional, so <CratisComponentsProvider> with no props also works. The full configuration surface is in the CratisComponentsProvider reference.
React Aria is an implementation dependency. Public props, parts, CSS variables, and event types are owned by Cratis.
Localize Components labels
Section titled “Localize Components labels”React Aria supplies its own locale data. Configure only labels owned by Components:
<CratisComponentsProvider value={{ locale: 'nb-NO', messages: { paginator: { navigation: 'Sidenavigasjon', first: 'Første side', previous: 'Forrige side', next: 'Neste side', last: 'Siste side', }, datePicker: { today: 'I dag', clear: 'Tøm', openCalendar: 'Åpne kalender', previousMonth: 'Forrige måned', nextMonth: 'Neste måned', }, }, }}> <YourApp /></CratisComponentsProvider>See the payoff
Section titled “See the payoff”CommandDialog takes the generated command, renders its fields and the OK/Cancel footer, keeps Add disabled until the form is valid, disables every button while the command executes, and closes only when the command succeeds:
import { useState } from 'react';import { Guid } from '@cratis/fundamentals';import { CommandDialog } from '@cratis/components/CommandDialog';import { InputTextField } from '@cratis/components/CommandForm';import { RegisterAuthor } from './Authors/RegisterAuthor';
export const AddAuthor = () => { const [id] = useState(() => Guid.create()); return ( <CommandDialog<RegisterAuthor> command={RegisterAuthor} title='Add author' okLabel='Add' initialValues={{ id }} > <InputTextField<RegisterAuthor> value={(command) => command.name} title='Name' /> </CommandDialog> );};The id is required but not typed by the user, so it goes in initialValues: the command is complete except for name from the moment the dialog opens. Setting a required value in onBeforeExecute instead is a common mistake — that callback runs only after the form has validated, so Add would never enable.
Open the dialog with Arc’s useDialog hook. It mounts the dialog only while it is open, so every Add author click gets a fresh id:
import { useDialog } from '@cratis/arc.react/dialogs';import { AddAuthor } from './AddAuthor';
export const Library = () => { const [AddAuthorDialog, showAddAuthor] = useDialog(AddAuthor); return ( <> <button type='button' onClick={() => void showAddAuthor()}> Add author </button> <AddAuthorDialog /> </> );};Run the app, click Add author, and type a name. Add enables, the dialog executes RegisterAuthor when you confirm, and it closes once the backend reports success. If the backend rejects the command, the dialog stays open and shows the validation messages against the fields. Cancel, the close button, and Escape close it without executing.
No isExecuting state, button wiring, or duplicate validation logic is required. If the C# command changes, the regenerated proxy makes this component fail compilation until you update it.
Choose how it looks
Section titled “Choose how it looks”Choose one styling posture:
- Import
themefor the Cratis baseline. - Define your own
--cratis-*token values for a product design system. - Add classes or ordinary HTML attributes through each component’s Cratis-owned
ptparts. - Target stable
data-cratis-partand state attributes when product CSS needs structural control.
Do not target React Aria class names or internal DOM structure. See Styling and Stable component parts.
If something doesn’t work
Section titled “If something doesn’t work”- Add never enables — a required command value is missing from
initialValues. See Troubleshooting. - Components render unstyled — the
tokensandstylesimports are missing or run after your product CSS in the wrong order. See Troubleshooting. - Commands or queries never reach the backend — check that
<Arc>wraps the app and that its settings and your dev-server proxy match the backend routes. See Troubleshooting.
You installed one UI package, imported Components-owned styles, mounted <Arc> and CratisComponentsProvider, and opened a command dialog generated from RegisterAuthor. Components owns the public React contract, Arc supplies command and query behavior, and React Aria supplies selected low-level interaction primitives internally.
Next, build a live library screen — the tutorial guides you step by step through a list-and-detail page with query-backed tables and command dialogs.
Where to go next
Section titled “Where to go next”- Build the library screen tutorial — follow one screen from a live table through command actions and list-and-detail composition
- Building a form
- Displaying data
- Choosing a component
- Troubleshooting — installation, styling, rendering, and form symptoms
- Migrate from Components 3
- Understand the UI foundation — including the capability profiles and capability matrix behind Foundation, Advanced React, and Spatial components