Skip to content

Flows

Where things go: splits, routes, loops and switchovers, with what moves along each path.

Installation & usage

npx @youj/cli add app-flow

Also installs alert, button, card, empty, segmented-control, skeleton, table, use-announcer, use-controllable-state, youj-core, youj-presets, youj-ui-core.

The CLI copies the block to blocks/app/flow.tsx with every component it uses, so it’s yours to edit.

Every prop is optional and falls back to the demo, so it renders as you see it until you pass your own. Give it your data, rewrite or translate its strings through copy, and connect its actions:

flow-view.tsx
'use client'

import { Flow, type FlowProps } from '@/blocks/app/flow'

export function FlowView({ stages, nodes, paths, ranges }: Pick<FlowProps, 'stages' | 'nodes' | 'paths' | 'ranges'>) {
  return (
    <Flow
      stages={stages}
      nodes={nodes}
      paths={paths}
      ranges={ranges}
      copy={{ title: 'Trial flow' }}
      onRangeChange={(range) => {
        // your code
      }}
      onSelectedChange={(id) => {
        // your code
      }}
      onRetry={() => {
        // your code
      }}
    />
  )
}

Reference

Props21 props

Props

Flow props
PropType
themeThemeInput

Wraps the card in this theme. Default: the theme around it.

–
embeddedboolean

Inside another app: a section named by an h2, without the page around the card.

default true

true
fillboolean

Take the whole width it's given instead of stopping at its natural width (768px at 100% scale).

default false

false
headingLevel1 | 2 | 3

The title's level. Default: 2 when embedded, else 1.

–
copyPartial<FlowCopy>

Any of the card's strings, to rewrite or translate.

–
localestring

Formats every figure (BCP 47). Default: copy.locale, else the app's locale (YoujProvider), else en-US.

–
stagesstring[]

The stages' names, first to last. Default: the demo's Source, Plan and Outcome.

–
nodesNode[]

The nodes, each in its stage, in the order they stack. Default: the demo's sources, plans and outcomes.

–
pathsPath[]

The routes through the stages and how many took each. Default: the demo's trials for the range shown.

–
formatIntl.NumberFormatOptions

Intl.NumberFormat options for every figure.

default whole numbers

whole numbers
rangesRange[]

The ranges the switch offers, each { id, label, name? }; fewer than two hides it. Default: 7, 30 and 90 days with the demo's paths, none with yours.

–
rangestring

The id of the range shown, controlled: pair it with onRangeChange. Default: uncontrolled.

–
defaultRangestring

The id of the range shown first, uncontrolled. Default: the first of your ranges, else 30d.

–
onRangeChange(range: string) => void

Called with the id of the range picked; answer with its paths.

–
selectedstring | null

The node kept lit, controlled (null for none): pair it with onSelectedChange. Default: uncontrolled.

–
defaultSelectedstring | null

The node kept lit first, uncontrolled.

default null

null
onSelectedChange(id: string | null) => void

Called with the node pressed, or null when it's let go.

–
loadingboolean

A skeleton in place of the chart while your data loads.

default false

false
errorReactNode

Shown in place of the chart when the data fails to load, with Retry when onRetry is set. Default: none.

–
onRetry() => void

Retries after an error. Default: none.

–
emptyReactNode

Replaces the message when nothing has flowed. Default: copy.empty and copy.emptyDescription.

–
Strings26 keys for copy

Strings

copy takes any of these keys; the rest keep their defaults. A key whose text holds a value (a count, a name) takes a function.

titledescriptionrangecountchartnodesnodeonwardfrompartpatharrowsummaryviewDatahideDatatablecolumnFromcolumnTocolumnValuecolumnShareannouncementloadingretryemptyemptyDescriptionlocale
Built from7 components
Accessibilitygroups, keyboard, live regions, motion

Accessibility

The flow's ribbons are decorative. Its steps are buttons on one tab stop: Up and Down move along a stage, Left and Right go to the nearest step of the next or last stage, and each is named with its figure, its share and where its people went next (or, at the end, where they came from). Enter pins a step and Escape lets it go. A new range is announced with its total, and View data shows every step to step as a table.

Routing flow names its strategy switch (a segmented control whose segments are pressed buttons) and announces the new blended cost in a polite live region. The flow is a named group described by its source and total, with each route in a list read with its rate and share; the drawing is decorative. The routes are a table with a header per column, and the fallback rule is a labelled switch and two named selects that turn off with it. The head's badge and the foot's caption say in words whether the policy is live or a draft, and a failed deploy says why in its button.

Queue flow lays steps out as a labelled group of buttons with aria-pressed, spoken with their name, kind, health and figure; the arrow keys move along the flow. The lens switch is labelled, the overview is a labelled stat group, and a hidden table lists every figure.

Loop route draws the map as an image whose text gives how many stops are done and how many bins are on board, and the list under it names each stop's state in words (the ring and the filled dots only echo it). Skip stop and Rush delivery announce their result, and the vehicle's ring holds still under reduced motion.

Switchover announces each step as it is logged. The four stages are an ordered list with aria-current="step" on the current one, the timeline is a labelled group, each source's carried power is a labelled group and its checks are an image with a spoken label. The simulation holds while it is off screen or the tab is hidden.

Under reduced motion pulses and pings stop and everything else changes in place.