ComponentsSidebarActivity
SidebarActivity
Keep background work visible while you navigate. Show AI runs, imports, exports, and work that needs attention in a compact sidebar region.
On this page
Install component source from the public registry, or use the local workspace package. Follow the setup guide first. The npm package is not published yet.
View registry files- Motion for React
(motion)· via shared Dethink componentsAnimations, transitions, and reduced-motion handling.
- React DOM
(react-dom)· via shared Dethink componentsPortals for rendering overlay content outside the normal component tree.
Shared foundation: React, clsx for conditional classes, tailwind-merge for resolving utility-class conflicts. Styles use Tailwind CSS and Dethink CSS variables.
Based on this component’s source and registry composition. Libraries used only in showcase examples are excluded.
Import the component into your page or component file.
import { SidebarActivity, type SidebarActivityItem } from "@dethink/components";Approve a brief, finish a run, or collapse the sidebar. The compact summary brings you back to the work that needs you.
Show sourceexamples/sidebar/activity.tsx
"use client";
import { useState, useSyncExternalStore } from "react";
import {
Button,
Sidebar,
SidebarActivity,
SidebarContent,
SidebarHeader,
SidebarProvider,
SidebarTrigger,
type SidebarActivityItem,
} from "@dethink/components";
import { Layers } from "lucide-react";
const subscribeHydration = () => () => {};
export function SidebarActivityExample() {
const hydrated = useSyncExternalStore(
subscribeHydration,
() => true,
() => false,
);
const [reviewed, setReviewed] = useState(false);
const [finished, setFinished] = useState(false);
const [empty, setEmpty] = useState(false);
const items: SidebarActivityItem[] = empty
? []
: [
{
id: "brief",
title: "Launch brief",
status: reviewed ? "complete" : "attention",
description: reviewed
? "Approved and ready to share"
: "Your approval is needed to continue",
action: reviewed
? undefined
: { label: "Approve brief", onAction: () => setReviewed(true) },
},
{
id: "index",
title: "Indexing documents",
status: finished ? "complete" : "running",
progress: 62,
description: finished
? "128 documents ready to search"
: "79 of 128 documents",
action: finished
? undefined
: { label: "Finish demo run", onAction: () => setFinished(true) },
},
{
id: "export",
title: "Weekly report",
status: "queued",
description: "Waiting for the index",
},
];
return (
<fieldset
disabled={!hydrated}
aria-label="Activity demo"
className="min-w-0 space-y-4"
data-testid="sidebar-activity-demo"
>
<div className="flex flex-wrap gap-2">
<Button size="sm" variant="outline" onClick={() => setEmpty(!empty)}>
{empty ? "Show activity" : "Clear activity"}
</Button>
<Button
size="sm"
variant="ghost"
onClick={() => {
setReviewed(false);
setFinished(false);
setEmpty(false);
}}
>
Reset demo
</Button>
</div>
<SidebarProvider motion="subtle" className="mx-auto max-w-64">
<Sidebar
className="h-[31rem] rounded-xl border"
aria-label="Activity workspace"
>
<SidebarHeader>
<div className="flex items-center gap-2 group-data-[collapsed=true]/sidebar:flex-col">
<span className="flex size-9.5 shrink-0 items-center justify-center">
<Layers
aria-hidden="true"
data-testid="activity-workspace-icon"
className="text-primary size-5 shrink-0"
/>
</span>
<span className="min-w-0 flex-1 truncate text-sm font-semibold group-data-[collapsed=true]/sidebar:hidden">
Studio workspace
</span>
<SidebarTrigger className="size-9.5" />
</div>
</SidebarHeader>
<SidebarContent>
<SidebarActivity items={items} label="Background work" />
</SidebarContent>
</Sidebar>
</SidebarProvider>
</fieldset>
);
}Place SidebarActivity inside SidebarContent so long activity lists can scroll with navigation.
Use it inside SidebarProvider and a Sidebar or SidebarMobile surface. Pass stable item IDs and a short, curated list. Your application owns data fetching, task execution, item ordering, and persistence. Progress is a percentage; finite values are clamped to 0–100 and omitted values show indeterminate progress for running items.
In a collapsed sidebar the summary expands navigation and focuses the activity region. Controlled collapse waits for your state update. For a permanent rail, pass onOpen to show your own details surface; without it the summary is informational. Mobile drawers always expose expanded activity details, even when desktop navigation is collapsed.
Native links handle navigation and native buttons invoke onAction. No routing, polling, cancellation, or task execution is built in. Keep item order stable while users interact; the example puts attention items first without automatically reordering them.
| Prop | What it does | Default |
|---|---|---|
itemsreadonly SidebarActivityItem[] | Stable id, title, status, optional description, progress and action for each item. | Not set |
status"running" | "attention" | "complete" | "queued" | Readable status plus a distinct icon. Only running items display progress. | Not set |
action{ label, href } | { label, onAction } | One native link or button action per item. | Not set |
label / emptyMessage / openLabelstring / ReactNode / string | Section title, empty content, and compact button label. | Activity / All caught up / Open activity |
statusLabels / formatSummaryPartial<Record<SidebarActivityStatus, string>> / (counts) => string | Localize status text and the accessible summary. Summary counts include all four statuses. | Not set |
onOpen() => void | Optional compact-summary action replacing expansion; useful for permanent rails. | Not set |
useSidebarState() => SidebarState | For custom sidebar extensions: resolved collapsed, side, variant, and setCollapsed. Requires SidebarProvider; respects the current mobile/desktop surface. | Not set |
Status uses text and icons alongside semantic colors. The list keeps native navigation and button behavior.
A polite summary announces changes to status counts, not every progress tick. Use statusLabels and formatSummary for localization. The region receives focus after compact expansion; native progress elements have item-specific accessible names. Tokenized styles inherit theme and density. Rendered interaction, axe, SSR/hydration, browser focus/mobile checks and registry install smoke tests cover the component. This is an additive component with no migration required.