Skip to content

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.

  • A React 19 application built with TypeScript. Components declares react and react-dom ^19.0.0 as peers.
  • An Arc frontend with generated proxies and experimentalDecorators/emitDecoratorMetadata enabled. The Arc tutorial’s first slice sets up the project, tsconfig.json, and Vite proxy that this page assumes.
  • @cratis/arc and @cratis/arc.react in 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.

  1. Install Components.

    Install Components 4
    npm install @cratis/components@^4

    React 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-metadata as peers. tsyringe is an optional peer: Components never imports it, and Arc React installs it as its own dependency. Keep @cratis/arc and @cratis/arc.react on 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.0
    npm 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.2

    Use Arc 22.16.0 or newer if you plan to use AutoCommandForm’s explicit field binding.

    pixi.js@^8.20.0 is another optional peer, needed only if you use Canvas or PivotViewer. 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.

  2. 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 appearance
    import { createRoot } from 'react-dom/client';
    import { App } from './App';
    createRoot(document.getElementById('root')!).render(<App />);

    tokens defines stable --cratis-* variables with conservative light defaults. styles supplies no-Preflight component structure in low-priority Cratis layers. theme adds 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 stable data-cratis-part elements or pt attributes.

    styles is every component’s CSS in one file. To download only the surfaces you mount, import @cratis/components/styles/base plus one <subpath>/styles entry 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 in src/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';
  3. Mount both providers around your application. <Arc> supplies the command and query runtime the generated proxies use; CratisComponentsProvider supplies 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>
    );

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:

.yarnrc.yml
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.

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.

RegisterAuthor proxy

CommandDialog

AllAuthors proxy

DataTable

Arc runtime

Cratis-owned semantic markup

React Aria behavior

--cratis-* tokens

React Aria is an implementation dependency. Public props, parts, CSS variables, and event types are owned by Cratis.

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>

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:

src/AddAuthor.tsx
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:

src/Library.tsx
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 one styling posture:

  • Import theme for 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 pt parts.
  • Target stable data-cratis-part and 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.

  • Add never enables — a required command value is missing from initialValues. See Troubleshooting.
  • Components render unstyled — the tokens and styles imports 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.