Templates
Onboarding checklist
Setup steps on the home page; progress, the next step open, done steps checked, a success state at the end and hiding with undo.
The onboarding checklist shows the first setup steps of a new workspace in order. Only the next step is open and it carries one action; finished steps are checked. The list can always be hidden, and a toast undoes the hiding.
Preview
Section titled “Preview”Press the button of the next step: the step is done, the progress bar fills and the following step opens. After the last step, the card turns into a success state. The brand and mode switches in the page header restyle the preview too.
pnpm add @bigbang/ui| Data | Type | Note |
|---|---|---|
| Steps | { title, text, action }[] |
Fixed order; each step has its own screen and counts as done on return. |
completed |
number |
Number of done steps from the server. |
| Hidden | boolean |
Stored per person; a hidden list does not come back on its own. |
import { Button, Card, Heading, Icon, Inline, ProgressBar, ResultState, Stack, Text, VisuallyHidden, motion, useToast } from '@bigbang/ui';import { useState } from 'react';import type { Lang } from '../../patterns/lang';import { AppShellTemplate } from '../../templates/app-shell/AppShellTemplate';
const copy = { tr: { page: 'Ana sayfa', pageDescription: 'Çalışma alanınızı birkaç adımda hazırlayın.', title: 'Başlarken', progress: 'Kurulum ilerlemesi', progressText: (done: number, total: number) => `${total} adımdan ${done} tamamlandı`, done: 'Tamamlandı', current: 'Sıradaki adım', hide: 'Listeyi gizle', hidden: 'Başlarken listesi gizlendi.', show: 'Geri getir', steps: [ { title: 'Profilinizi tamamlayın', text: 'Adınızı ve fotoğrafınızı ekleyin; ekip sizi tanısın.', action: 'Profili aç' }, { title: 'Ekip arkadaşı davet edin', text: 'E-posta adresiyle davet gönderin; rolünü sonra değiştirebilirsiniz.', action: 'Davet gönder' }, { title: 'İlk projeyi oluşturun', text: 'Proje, kayıtları ve görevleri bir arada tutar.', action: 'Proje oluştur' }, { title: 'Bildirim tercihlerini seçin', text: 'Hangi olaylarda e-posta alacağınızı belirleyin.', action: 'Tercihleri aç' }, ], completedTitle: 'Çalışma alanınız hazır', completedText: 'Tüm adımları tamamladınız. Bu kartı artık kapatabilirsiniz.', close: 'Kartı kapat', }, en: { page: 'Home', pageDescription: 'Get your workspace ready in a few steps.', title: 'Getting started', progress: 'Setup progress', progressText: (done: number, total: number) => `${done} of ${total} steps done`, done: 'Done', current: 'Next step', hide: 'Hide the list', hidden: 'Getting started list hidden.', show: 'Bring back', steps: [ { title: 'Complete your profile', text: 'Add your name and photo so the team knows you.', action: 'Open profile' }, { title: 'Invite a teammate', text: 'Send an invitation by email; you can change their role later.', action: 'Send invitation' }, { title: 'Create the first project', text: 'A project keeps records and tasks together.', action: 'Create project' }, { title: 'Choose notification preferences', text: 'Decide which events send you an email.', action: 'Open preferences' }, ], completedTitle: 'Your workspace is ready', completedText: 'You have done every step. You can close this card now.', close: 'Close the card', },};
export type OnboardingChecklistBlockProps = { lang?: Lang; /** How many steps are already done on first render. */ completed?: number;};
/** * A getting-started checklist on the home page: progress, the next step open with its action, * done steps checked, a success state at the end and a hide action with undo. */export function OnboardingChecklistBlock({ lang = 'tr', completed = 1 }: OnboardingChecklistBlockProps) { const t = copy[lang]; return ( <AppShellTemplate lang={lang} current="home" title={t.page} description={t.pageDescription} width="md"> <Checklist lang={lang} completed={completed} /> </AppShellTemplate> );}
function Checklist({ lang, completed }: { lang: Lang; completed: number }) { const t = copy[lang]; const toast = useToast(); const total = t.steps.length; const [done, setDone] = useState(() => Math.min(completed, total)); const [pending, setPending] = useState(false); const [visible, setVisible] = useState(true); const titleId = `onboarding-${lang}`;
// The pause stands in for the step's own screen; the demo marks it done on return. const complete = () => { setPending(true); setTimeout(() => { setPending(false); setDone((value) => Math.min(value + 1, total)); }, 600); };
const hide = () => { setVisible(false); toast.show({ title: t.hidden, action: { label: t.show, onClick: () => setVisible(true) } }); };
if (!visible) return null;
return ( <Card variant="outlined" padding="lg" className={motion.reveal}> <section {...(done === total ? { 'aria-label': t.title } : { 'aria-labelledby': titleId })}> {done === total ? ( <ResultState tone="success" headingLevel={2} // Focus moves to the result only when the last step was just finished here. focusOnMount={completed < total} title={t.completedTitle} description={t.completedText} actions={ <Button variant="secondary" onClick={hide}> {t.close} </Button> } /> ) : ( <Stack gap="lg"> <Inline justify="between" align="center" gap="md" wrap> <Heading level={2} size="md" id={titleId}> {t.title} </Heading> <Button variant="tertiary" size="sm" onClick={hide}> {t.hide} </Button> </Inline> <ProgressBar label={t.progress} value={done} max={total} valueText={t.progressText(done, total)} description={t.progressText(done, total)} showValue={false} size="sm" /> <ol className="flex flex-col gap-xs"> {t.steps.map((step, index) => { const state = index < done ? 'done' : index === done ? 'current' : 'todo'; return ( <li key={step.title} aria-current={state === 'current' ? 'step' : undefined} className={['flex gap-md rounded-md p-md', state === 'current' ? 'bg-surface-sunken' : ''].join(' ')} > <span className="mt-xxs flex size-6 shrink-0 items-center justify-center" aria-hidden="true"> {state === 'done' ? ( <Icon name="circle-check" tone="success" className={motion.success} /> ) : ( <span className={['flex size-5 items-center justify-center rounded-full border type-label-sm', state === 'current' ? 'border-line-selected text-fg-default' : 'border-line-default text-fg-subtle'].join(' ')}> {index + 1} </span> )} </span> <Stack gap="xs" className="min-w-0 flex-1"> <Text weight="medium" tone={state === 'done' ? 'subtle' : 'default'} {...(state === 'done' ? { className: 'line-through' } : {})}> {state === 'done' ? <VisuallyHidden>{`${t.done}:`}</VisuallyHidden> : null} {state === 'done' ? ' ' : null} {step.title} </Text> {state === 'current' ? ( <div className={motion.collapsible}> <Stack gap="sm"> <Text size="sm" tone="subtle"> {step.text} </Text> <div> <Button size="sm" loading={pending} onClick={complete} endIcon={<Icon name="arrow-right" />}> {step.action} </Button> </div> </Stack> </div> ) : null} </Stack> </li> ); })} </ol> </Stack> )} </section> </Card> );}Structure
Section titled “Structure”- AppShell template (
width="md"),h1“Home”. - A Card with the
h2“Getting started” and “Hide the list”. - An
smProgressBar: “1 of 4 steps done”. - An ordered list (
ol): done steps with a check icon and a struck-through title; the next step open with its text and action button; the rest only a number and title. - When every step is done, the card becomes a ResultState with an
h2. - Hiding and bringing back through a Toast.
Motion
Section titled “Motion”The card enters with motion.reveal. The next step’s content opens with motion.collapsible; a done step’s check grows in with motion.success; the progress bar fills with motion.progress. With reduced motion, scaling and sliding stop.
Accessibility
Section titled “Accessibility”- The list is a real
ol; the next step carriesaria-current="step". - Done steps are read with a hidden “Done:” prefix; strike-through and the green icon never carry the meaning alone.
- The progress bar value is read as “1 of 4 steps done”, not as a percentage.
- When the last step is finished here, focus moves to the success heading so the result is read at once; a page that opens with a finished list does not move focus.
- F6 reaches the “Bring back” button in the notification region.
Components used
Section titled “Components used”Card, ProgressBar, ResultState, Button, Icon, Toast, VisuallyHidden. Patterns: Empty states, Notifications.