Skip to content
Slicekit

Frontend

Adding a frontend feature

Build a React feature with typed API calls, translated forms and the shared authentication flow.

View .md
On this page

Keep a feature’s API calls, wire types, hooks, schemas and UI together under frontend/src/features/<slice>/. Start with Frontend overview for the stack and routing conventions.

Wire types and API calls

Define camelCase request and response types from the endpoint’s transport records. Commands can include values supplied by the server, such as the current user ID, so their fields are not automatically request fields. Preserve nullable response values and distinguish form input values from the request sent over the wire.

Use frontend/src/features/api-keys/types.ts and api.ts as the current example, together with api/src/Slicekit.Api/Endpoints/v1/ApiKeys/CreateApiKeyEndpoint.cs. For downloads, use the data-export slice. All calls go through the API client: JSON uses apiFetch, downloads use apiBlob, and uploads pass FormData without setting a multipart Content-Type manually.

Run node scripts/check-contracts.mjs from the repository root after changing a wrapper or wire type. It checks those application types against a fresh API export; no generated client needs updating.

Form schemas and errors

Create Zod schemas as factories taking i18next’s TFunction, and rebuild them when the locale changes. Use keys that exist in both locales and provide every interpolation value the message requires. Follow Forms and Internationalisation.

Read the current API-key schemas.ts and components/CreateApiKeyDialog.tsx for the working form and request conversion. Do not copy API-key constraints into a feature that does not share them: a key needs at least one permission, and credential creation requires step-up before submission. Keep password and re-auth proof fields in the request when the operation needs them. See Step-up re-authentication.

Use React Hook Form with showFormError from frontend/src/shared/ui/form-error.ts. It applies server field errors and shows a translated fallback when no field error was handled. A catch block that only calls applyToForm can silently swallow a non-field API error. Keep challenge and re-authentication transitions in the owning feature before applying the ordinary form-error helper.

Server state and UI

Use TanStack Query for server data. Include pagination, filters and other request inputs in query keys, export keys for related mutations, and invalidate the data a successful mutation changes. The API-key hooks.ts shows list keys and invalidation. Reuse meQueryKey from features/account/hooks.ts for current-user invalidation and currentUserQueryOptions from features/account/queries.ts when fetching that same data outside a hook.

Render failed queries as retryable errors, including failed refetches with old data still cached. A failure does not establish that a list is empty or a credential is unlinked. Keep search and filter controls available while the failed result area shows LoadError.

Use translated labels, shared confirmation dialogs for irreversible actions and the existing step-up flow for credential or identity changes. Avoid duplicating those flows inside a new feature.

Routes and permissions

Create or extend a file under frontend/src/routes/. Underscore-prefixed segments are pathless layouts. _app.settings.api-keys.tsx shows route composition with feature components. Vite generates routeTree.gen.ts during development and builds; never edit the generated file.

Place navigation in the relevant workflow, such as the settings layout. Mirror new permissions in shared/auth/permissions.ts and follow Frontend permissions when hiding actions or navigation. The server still enforces authorization on every request.

Verify

  • Run the contract checker after changing wire types or endpoint wrappers.
  • From frontend/, run pnpm typecheck, pnpm lint and pnpm test.
  • Exercise valid and invalid submissions, non-field API failures, language changes and permission-denied behavior.
  • Manually verify cookies, re-authentication, redirects and interactive state transitions when changing those flows.

Live demo

Explore the running app

No sign-up. Pick an account to open the demo with its credentials prefilled, or open it and sign in yourself.

Open without signing in

Credentials are prefilled. Shared password Slicekit-Demo-2026!.