The Workflow Selector Has No Tabs
The interactive workflow section on the homepage lets visitors pick between three example workflows. Visually it looks like a tab bar. Under the hood, we didn't use the ARIA tabs pattern.
Here is what the markup looks like:
<div className="workflow-controls" aria-label="Choose an example workflow">
{workflows.map((workflow, index) => (
<button
key={workflow.title}
type="button"
aria-pressed={active === index}
aria-controls="workflow-example"
onClick={() => setActive(index)}
>
...
</button>
))}
</div>
<div
className="workflow-example"
id="workflow-example"
aria-live="polite"
aria-atomic="true"
>
<div key={active} className="workflow-scene">...</div>
</div>
Why not tabs
The full ARIA tabs pattern requires role="tablist" on the container, role="tab" on each button, aria-selected instead of aria-pressed, role="tabpanel" on the content area, and aria-labelledby linking each panel back to its tab. It also implies keyboard behavior: arrow keys should move focus between tabs. For a content switcher on a marketing homepage, that overhead is real work with no real payoff.
aria-pressed announces each button as a toggle: "Draft the quote, button, pressed" or "See the whole picture, button, not pressed." aria-controls links each button to the panel by matching id workflow-example, giving screen readers the connection without any role infrastructure. The aria-label on the container group ("Choose an example workflow") supplies context that the buttons themselves don't.
The live region handles content changes
When active updates, the aria-live="polite" region queues an announcement at the next natural pause. aria-atomic="true" tells the screen reader to read the entire region, not just the changed part. So a screen reader user hears the full new workflow: trigger sentence, agent task description, output label, checklist items, footer note. The whole thing, in order.
The animation side
The inner workflow-scene div carries key={active}. React reconciliation sees a new key and remounts the element rather than patching it, which resets the CSS animation. The rule is animation: studio-rise .45s var(--studio-spring) both -- the same spring used on the hero heading, but faster. Every button click makes the content rise in from below as if it just loaded.
These three things happen together on each click: the button's aria-pressed state flips, the live region queues a content announcement, and the new content animates in. No extra coordination between them. The key is the only coupling between state change and animation.
The tradeoff
A screen reader following the ARIA tabs spec could navigate panel to panel with arrow keys. That convention doesn't apply here. The three workflow examples are interchangeable snapshots, not sequential content. There is no right order to read them in, and arrow-key navigation would add keyboard complexity without serving anyone. Each button sits in normal tab order; clicking it triggers the live region and replays the animation. That's the whole contract.