> [Agent navigation index](/llms.txt)

# Build managed React applications

Create and operate a browser-only managed React SPA or Contentful App with Brix-owned runtime and Vite integration.

## Create a managed React SPA

Create a standalone app:

```sh
brix create react-app customer-portal
cd customer-portal
brix dev

```

From a Brix workspace root, omit `--version`; the new member uses the workspace's exact Brix version and a bare name is placed under `apps/`:

```sh
brix create react-app customer-portal
brix doctor#customer-portal
brix dev#customer-portal

```

The generated manifest declares `brix.project: "react-application"`. It has a root `index.html`, `src/main.tsx`, `src/App.tsx`, `src/brix.ts`, and this Vite configuration:

```ts
import { defineBrixReactConfig } from "@brix/react/vite";

export default defineBrixReactConfig();

```

`defineBrixReactConfig` configures the managed React JSX runtime, deduplicates React and ReactDOM, supplies browser-safe aliases, and adds the Brix Vitest configuration. Its optional `vite` value accepts the supported Brix Vite escape hatch as an object or a function of the Vite environment:

```ts
export default defineBrixReactConfig({
  vite: ({ mode }) => ({
    base: mode === "production" ? "/portal/" : "/",
    define: { __APP_VARIANT__: JSON.stringify(mode) },
  }),
});

```

Do not replace managed entries, output, JSX settings, or Brix plugins through that escape hatch.

## Use the managed runtime

Import React APIs and types from `@brix/react`, not directly from `react`. Mount through the client entry point:

```tsx
import { StrictMode } from "@brix/react";
import { createRoot } from "@brix/react/client";
import { App } from "./App.tsx";

const element = document.getElementById("root");
if (!element) throw new Error("React application root is missing");

createRoot(element).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

```

The root adapter also exports Brix's React bindings:

- `useApi` for contract-aware requests
- `useSignal` and `useComputed` for React signal integration
- `useStorage`, `useLocalStorage`, and `useSessionStorage`
- `TranslationProvider` and `createTranslationHooks`
- the supported React runtime, hooks, events, elements, and component types

Define browser-safe contracts with `defineBrix` in `src/brix.ts`:

```ts
import { defineBrix } from "brix/contracts";

export const brix = defineBrix();
export const { createApiContract, executeApi, getPath } = brix;

```

Application components can then combine project-bound contracts with React hooks:

```tsx
import { useApi } from "@brix/react";
import { productApiContract } from "@commerce/contracts";

export function Product({ productId }: { productId: string }) {
  const request = useApi(productApiContract, {
    baseUrl: "https://api.example.com",
  });

  if (request.isLoading.value) return <p>Loading…</p>;
  if (request.isError.value) return <p>Request failed: {request.error.value?.message}</p>;
  if (request.data.value) return <h1>{request.data.value.name}</h1>;
  return (
    <button onClick={() => void request.execute({ params: { productId } })}>Load product</button>
  );
}

```

The contract package is a contextual application dependency: link it in a workspace before importing it. Consult [API routes](/docs/api-routes) and the [API reference](/docs/api-reference) for the installed `useApi` signature.

## Understand the application boundary

A managed React application builds once to `dist`. It is not a Brix server application and has:

- no Hono API or page route implementation
- no SSR, `createBrixApp`, or Node `start` command
- no Preact islands or hydration directives
- no Panda integration; use the React application's chosen CSS approach
- no managed Brix Storybook support

Shared contracts let the React browser call a separately deployed BFF; they do not make the deployments same-origin. Pass that BFF's deployed origin as `baseUrl`, and configure the BFF to allowlist the browser origin with its CORS middleware. See [workspaces](/docs/workspaces) and the [caching guide](/docs/caching).

## Create a Contentful App

Use the dedicated preset rather than adding Contentful packages by hand:

```sh
brix create contentful-app editorial-tools

```

Within a workspace:

```sh
brix create contentful-app editorial-tools

```

This remains a `react-application`, but records the Contentful integration and adds exact compatible SDK, Forma 36, icon, and app-script dependencies. The generated Vite config uses a relative base required by uploaded Contentful assets:

```ts
import { defineBrixReactConfig } from "@brix/react/vite";

export default defineBrixReactConfig({ vite: { base: "./" } });

```

Import the managed surfaces through Brix:

```tsx
import { useEffect } from "@brix/react";
import { Button, GlobalStyles, Heading } from "@brix/react/contentful";
import { PlusIcon } from "@brix/react/contentful/icons";
import { init, type KnownAppSDK } from "brix/contentful/app";

```

The generated entry calls `init`, renders with its SDK, and handles the app configuration location. Preserve `base: "./"`; `brix doctor` reports drift. Continue with the [Contentful guide](/docs/contentful).

Continue with [integrate an external react host](/docs/react-external).
