Flow
Runs steps in one place, keeping what was typed and moving focus for you.
SourcePackage @weft-js/warp
Preview
tsx
import { state } from '@weft-js/core'import { Button, Flow, Input, Row, Select, Stack, Text } from '@weft-js/warp'export function NewProject() { const step = state('repo') const name = state('storefront') const at = () => WIZARD.indexOf(step.value) const steps = [ { id: 'repo', label: 'Repository', render: () => <Input label="Project name" data-autofocus value={name.value} onInput={e => (name.value = e.currentTarget.value)} /> }, { id: 'build', label: 'Build', render: () => <Select label="Framework" options={FRAMEWORKS} defaultValue="weft" /> }, { id: 'review', label: 'Review', render: () => <Text>Ready to deploy {name.value} to eu-west.</Text> }, ] return ( <Stack gap="group"> <Text role="label">Step {at() + 1} of 3</Text> <Flow steps={steps} step={step} /> <Row gap="related" justify="end"> <Button emphasis="ghost" tone="neutral" aria-disabled={at() === 0 ? 'true' : undefined} onClick={() => { if (at() > 0) step.value = WIZARD[at() - 1]! }}>Back</Button> <Button onClick={() => (step.value = WIZARD[(at() + 1) % 3]!)}>{at() === 2 ? 'Deploy' : 'Continue'}</Button> </Row> </Stack> )}const FRAMEWORKS = [{ value: 'vite', label: 'Vite' }, { value: 'next', label: 'Next.js' }, { value: 'weft', label: 'weft' }]const WIZARD = ['repo', 'build', 'review']Installation
npm install @weft-js/warpUsage
tsx
import { Flow } from '@weft-js/warp'When to use
Use it for
- A task that takes a few steps on one screen
Reach for something else
- Tabs, when people can go to any part in any order
Accessibility
- The step is announced on arrival, and focus goes to
data-autofocusor the step's title.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
steps | FlowStep[] | — | An id, a label to announce, and render. |
step | string | State<string> | — | The current id: a state, or a value. |
defaultStep | string | — | The first step, when you do not own it. |
history | string | boolean | — | Keeps the step in the URL. true uses ?step=. |
announce | boolean | false | Says "Step 2 of 4, Shipping" politely. |
| Event | Type | Default | Description |
|---|---|---|---|
onStepChange | ((id: string) => void) | — | Called on each change. |
Parts
Every element carries a stable name, so you can style it from your own CSS: [data-scope="flow"] [data-part="step"]
step