Onboarding
Configure and extend the mobile onboarding flow with schema, step config, and filters.
What It Does
apps/mobile uses a QuickForm stepper onboarding flow that runs before the main app stack.
The flow is schema-driven and extensible via filters.
When To Use
- You need to collect user profile data before first app usage.
- You need app-specific onboarding steps on top of the default flow.
- You need route-level onboarding extensions (
/onboarding/[onboardingPath]).
Prerequisites
- Authenticated user session.
completedOnboardingfield available on user record.apps/mobile/config/onboarding.config.tsxconfigured.
Flow Overview
app/(app)/_layout.tsxredirects users with!completedOnboardingto/onboarding.app/onboarding/index.tsxrenders the default stepper flow.app/onboarding/[onboardingPath]/index.tsxsupports custom onboarding routes from filters.
How To Use
Define schema and default steps.
import { z } from 'zod'; export const onboardingSchema = { userImageUrl: z.string().optional().nullable(), userName: z.string().trim().min(1).max(64), userPhone: z.string().trim().max(16).optional().or(z.literal('')), userEmail: z.string().email(), userRole: z.enum(['designer', 'programmer', 'product_manager', 'tester', 'marketer']), }; export const onboardingStepsConfig = [ { type: 'step', label: 'User', settings: [ { type: 'user_media', slug: 'userImageUrl' }, { type: 'text', slug: 'userName', label: 'Name' }, { type: 'text', slug: 'userEmail', label: 'Email', disabled: true }, ], }, { type: 'step', label: 'Profession', settings: [{ type: 'question_select', slug: 'userRole' }], }, ];
Render onboarding using schema/steps filters.
import { QuickForm } from '@kit/native-ui/quick-form';
import { applyAsyncFilter, useApplyFilter } from '@kit/utils/filters';
import { onboardingSchema, onboardingStepsConfig } from '~/config/onboarding.config';
const schema = useApplyFilter('get_onboarding_schema', onboardingSchema);
const steps = useApplyFilter('get_onboarding_steps_config', onboardingStepsConfig, { clientTrpc });
const extraInputs = useApplyFilter('get_onboarding_extra_inputs', {});
<QuickForm config={onboardingConfig} inputs={extraInputs} onSubmit={handleSubmit} />Update onboarding completion + redirect.
Default submit path in onboarding/index.tsx:
- calls
clientTrpc.updateUser.fetch(data); - refetches
getUserquery; - computes redirect via
applyAsyncFilter('on_onboarding_submit', '/', ...); - pushes final route.
Add new fields and steps safely.
- Add Zod field in
onboardingSchema. - Add matching input node in
onboardingStepsConfig. - Ensure submit handler forwards this field to API mutation.
- If needed, register extra input component through
get_onboarding_extra_inputsfilter.
Advanced Extension Points
| Filter | Purpose |
|---|---|
get_onboarding_schema | Extend base schema without editing package internals. |
get_onboarding_steps_config | Insert/reorder/remove steps. |
get_onboarding_extra_inputs | Register custom QuickForm input components. |
on_onboarding_submit | Customize post-submit redirect + side effects. |
render_onboarding_path | Render custom route content in /onboarding/[onboardingPath]. |
Filter API
Mobile onboarding is extended through organization onboarding filters registered from the shared onboarding package layer.
| Filter | Parameters | Return | Registered By (package file) | Initialized In (app entrypoint) | Environment |
|---|---|---|---|---|---|
get_onboarding_schema | {} | QuickFormSchemaMap | kit/organization/src/shared/filters/use-filters/use-onboarding-filters.tsx | apps/mobile/hooks/use-filters.ts (useOrgFilters) | client |
get_onboarding_steps_config | { clientTrpc: TrpcClientWithQuery<Router<unknown>> } | QuickFormStepConfig<QuickFormSchemaMap>[] | kit/organization/src/shared/filters/use-filters/use-onboarding-filters.tsx | apps/mobile/hooks/use-filters.ts (useOrgFilters) | client |
get_onboarding_extra_inputs | {} | SettingsInputsBase | kit/organization/src/shared/filters/use-filters/use-onboarding-filters.tsx | apps/mobile/hooks/use-filters.ts (useOrgFilters) | client |
render_onboarding_path | { onboardingPath: string; clientTrpc: TrpcClientWithQuery<Router<unknown>>; queryClient: QueryClient; defaultSchema: QuickFormSchemaMap; defaultSteps: QuickFormStepConfig<QuickFormSchemaMap>[] } | null | { config: QuickFormConfig<QuickFormSchemaMap>; inputs: SettingsInputsBase; onSubmit: (data: unknown) => Promise<void> } | kit/organization/src/shared/filters/use-filters/use-onboarding-filters.tsx | apps/mobile/hooks/use-filters.ts (useOrgFilters) | client |
on_onboarding_submit | { data: Record<string, unknown>; clientTrpc: TrpcClientWithQuery<Router<unknown>>; queryClient: QueryClient } | string | kit/organization/src/shared/filters/use-filters/use-onboarding-filters.tsx | apps/mobile/hooks/use-filters.ts (useOrgFilters) | client |
get_translations | { language: string; namespace: string } | Record<string, string> | null | kit/organization/src/native/filters/use-filters/use-translation-filters.tsx | apps/mobile/hooks/use-filters.ts (useOrgFilters) | client |
Init Checklist
- Keep
useOrgFilters({ clientTrpc, orgConfig })inapps/mobile/hooks/use-filters.ts. - Keep
applyAsyncFilter('get_translations', ...)inapps/mobile/config/i18n.config.ts.
MCP Context
capability: onboarding_mobile_flow entrypoints: - apps/mobile/config/onboarding.config.tsx - apps/mobile/app/onboarding/index.tsx - apps/mobile/app/onboarding/[onboardingPath]/index.tsx - apps/mobile/app/(app)/_layout.tsx - apps/mobile/hooks/use-filters.ts - apps/mobile/config/i18n.config.ts - kit/organization/src/shared/filters/use-filters/use-onboarding-filters.tsx - kit/organization/src/native/filters/use-filters/use-onboarding-filters.tsx - kit/organization/src/native/filters/use-filters/use-translation-filters.tsx inputs: - onboarding_schema - onboarding_steps - onboarding_filter_overrides outputs: - gated_onboarding_experience constraints: - user fields in steps must exist in schema - completedOnboarding gating must stay consistent with app layout redirect side_effects: - updates user profile fields and onboarding completion status
Agent Recipe
- Extend schema and steps in
onboarding.config.tsx. - Add custom inputs/logic through onboarding filters instead of hardcoding package internals.
- Verify
completedOnboardingredirect behavior in(app)/_layout.tsxand onboarding submit path.
Troubleshooting
- If fields do not render, verify input type is registered in onboarding inputs map/filters.
- If user always returns to onboarding, verify
updateUsermutation persists completion fields and user query refresh occurs. - If custom onboarding path shows 404 (
Unmatched), verifyrender_onboarding_pathfilter returns content.
Related
User Settings
Integrate auth-related controls into mobile settings pages.
Translations
Configure i18next translations in apps/mobile with package translation filters.
How is this guide?
Last updated on 3/27/2026