Navigation
BusyRegion
Marks content that is still arriving, such as a streamed answer, so comp0 parts inside stay quiet and keep focus where it is.
When to use it: Use it around progressively rendered content, such as model-generated answers. Messages already acts as a busy region for its conversation.
Example
import { useEffect, useState } from "react";
import { BusyRegion, Button, Status } from "@comp0/react";
const answerLines = [
"Check the color contrast of the primary button.",
"Give every icon-only control an accessible name.",
"Keep focus where it is while the answer is written.",
];
export function Example() {
const [lines, setLines] = useState(0);
const [asked, setAsked] = useState(false);
const writing = asked && lines < answerLines.length;
useEffect(() => {
if (!writing) return;
const timer = setTimeout(() => setLines((current) => current + 1), 700);
return () => clearTimeout(timer);
}, [writing, lines]);
function ask() {
if (writing) return;
setLines(0);
setAsked(true);
}
let announcement = "";
if (!writing && lines > 0) announcement = "Answer ready.";
return (
<section aria-labelledby="busy-title" className="flex w-full max-w-md flex-col gap-3">
<h2 id="busy-title" className="font-semibold text-zinc-950 dark:text-white">
Review assistant
</h2>
<BusyRegion
busy={writing}
className="flex min-h-32 flex-col gap-2 rounded-xl border border-zinc-950/10 bg-white p-4 data-busy:border-teal-600/40 dark:border-white/10 dark:bg-zinc-900"
>
<p className="text-sm text-zinc-700 dark:text-zinc-300">
{lines === 0 ? "Ask for a review to see the answer arrive line by line." : "Next steps:"}
</p>
<ol className="list-decimal pl-5 text-sm text-zinc-900 dark:text-zinc-100">
{answerLines.slice(0, lines).map((line) => (
<li key={line}>{line}</li>
))}
</ol>
</BusyRegion>
<Status className="text-sm text-zinc-600 dark:text-zinc-400">{announcement}</Status>
<Button
onClick={ask}
className="self-start rounded-lg bg-teal-700 px-3 py-2 text-sm font-medium text-white outline-teal-600 focus-visible:outline-2 dark:bg-teal-400 dark:text-zinc-950 dark:outline-teal-300"
>
Ask again
</Button>
</section>
);
}Anatomy
Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.
A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.
BusyRegion
A wrapper that sets aria-busy and tells comp0 parts inside that their data may be incomplete. Owns a DOM element.
Step by step
- 1
Add the main part
Wrap the streamed content in BusyRegion and set busy while it is still arriving.
- 2
Add the supporting parts
Render whatever has arrived so far; charts, tables, tabs, and other comp0 parts accept partial data without remounting.
- 3
Make the behavior clear
Set busy to false when the content is complete. Warnings about invalid data are reported once at that moment, and nothing inside moves focus until then.
Exampletsx <BusyRegion busy={streaming}> <p>{answerSoFar}</p> </BusyRegion>;
Keyboard
Forms and accessibility
BusyRegion does not create form values. Inputs inside keep their values while the content grows.
Accessibility checklist
- aria-busy tells assistive technology to wait for the finished content, so BusyRegion adds no live region of its own and never announces completion by itself.
- To announce completion once, keep a short Status outside the region (as in the example) or make the region itself a log or status. Do not do both, or the answer is announced twice.
- While busy, no comp0 part moves focus: overlays do not take initial focus, Tour and Toast do not claim focus, and arrow-key handling still works only in response to the user.
- Incomplete data is not invalid data: warnings about malformed values wait until busy turns off, and the fallback rendering is the same either way.
- Do not disable the control that started the response while it streams; disabling a focused button drops focus. Ignore the click instead.
API reference
import { BusyRegion, Button, Status } from "@comp0/react";BusyRegion
DOM elementA wrapper that sets aria-busy and tells comp0 parts inside that their data may be incomplete.
| Prop | Type | Description |
|---|---|---|
busy | boolean | Marks the content as still being assembled. Sets aria-busy and data-busy; regions nest, so a part is busy while any ancestor region is. |
as | ElementType | Renders another element in place of the default; Fragment merges the props into its single child. |
Style hooks
Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.
BusyRegion
| Style hook | Meaning |
|---|---|
[data-busy] | The region, or an ancestor region, is still receiving content. |