Rendered from the shared Frontfriend stories with React Base, the same
preview Studio shows. Styling comes from your Design System; the code below
is native to Reka UI.
Installation
Complete project setup first. Your configuration
must select vue/reka and include your Design System ID.
pnpm exec frontfriend download trace -f vue --primitive reka
Review dependencies reported by the downloader and keep your source
changes in version control.
Usage
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { TraceCollapsible } from "@/components/ui/trace";
import { TraceCollapsibleTrigger } from "@/components/ui/trace";
import { TraceLine } from "@/components/ui/trace";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceTitle } from "@/components/ui/trace";
import { TraceDescription } from "@/components/ui/trace";
import { TraceCollapsibleContent } from "@/components/ui/trace";
import { reactive } from "vue";
const args = reactive(
{
"status": "running",
"text": "Inspect sources",
"open": true,
"disabled": false,
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown> & {
status?: "done" | "running" | "error" | "pending";
},
);
const status = {
done: undefined,
running: "running",
error: "error",
pending: "pending",
} as const;
const label = {
done: "Complete",
running: "Running",
error: "Error",
pending: "Pending",
};
</script>
<template>
<div style="width: min(32rem, calc(100vw - 4rem))">
<Trace
><TraceCollapsible v-model:open="args.open" :disabled="args.disabled">
<TraceCollapsibleTrigger
><TraceLine :status="status[args.status]"
><TraceIcon><Icon name="Search" /></TraceIcon
><TraceTitle>{{ label[args.status] }}: {{ args.text }}</TraceTitle
><TraceDescription>2 files</TraceDescription></TraceLine
></TraceCollapsibleTrigger
>
<TraceCollapsibleContent
>The task inspected two source files.</TraceCollapsibleContent
>
</TraceCollapsible></Trace
>
</div>
</template>
Status
Set status to running, error or pending. Omit it for a normal or completed step. Include status in the visible text. Running uses a shimmer; reduced motion turns it off. Trace does not store tasks or infer a parent status.
Composition
A line is a span. Put it inside an anchor or an overlay trigger to make it interactive. The trigger owns keyboard and focus behavior. The outer panel keeps its native height animation. Icons are decorative by default.
Controlled state
Bind open with v-model:open on TraceCollapsible, or use :open with @update:open. Use :default-open for an uncontrolled initial value. For automatic expansion while running, let a user choice override the running value. The Running Override example uses :open="open ?? running". The default scoped slot exposes { open }. TraceCollapsibleContent supports :force-mount; its class styles the inner wrapper.
Examples
Default
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { TraceLine } from "@/components/ui/trace";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceTitle } from "@/components/ui/trace";
import { TraceDescription } from "@/components/ui/trace";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<div style="width: min(32rem, calc(100vw - 4rem))">
<Trace>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: read the request</TraceTitle
><TraceDescription>0.4 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Search" /></TraceIcon
><TraceTitle>Complete: searched four files</TraceTitle
><TraceDescription>1.2 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: prepared the answer</TraceTitle></TraceLine
>
</Trace>
</div>
</template>
Statuses
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { TraceLine } from "@/components/ui/trace";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceTitle } from "@/components/ui/trace";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<Trace>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: request received</TraceTitle></TraceLine
>
<TraceLine status="running"
><TraceIcon><Icon name="Search" /></TraceIcon
><TraceTitle>Running: searching files</TraceTitle></TraceLine
>
<TraceLine status="error"
><TraceIcon><Icon name="X" /></TraceIcon
><TraceTitle>Error: source is unavailable</TraceTitle></TraceLine
>
<TraceLine status="pending"
><TraceIcon><Icon name="Clock" /></TraceIcon
><TraceTitle>Pending: prepare the answer</TraceTitle></TraceLine
>
</Trace>
</template>
Default Open
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { TraceCollapsible } from "@/components/ui/trace";
import { TraceCollapsibleTrigger } from "@/components/ui/trace";
import { TraceLine } from "@/components/ui/trace";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceTitle } from "@/components/ui/trace";
import { TraceDescription } from "@/components/ui/trace";
import { TraceCollapsibleContent } from "@/components/ui/trace";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<Trace
><TraceCollapsible default-open>
<TraceCollapsibleTrigger
><TraceLine
><TraceIcon><Icon name="Search" /></TraceIcon
><TraceTitle>Complete: inspected sources</TraceTitle
><TraceDescription>3 files</TraceDescription></TraceLine
></TraceCollapsibleTrigger
>
<TraceCollapsibleContent
>Read the component source, its style rules and the
tests.</TraceCollapsibleContent
>
</TraceCollapsible></Trace
>
</template>
Nested
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { TraceCollapsible } from "@/components/ui/trace";
import { TraceCollapsibleTrigger } from "@/components/ui/trace";
import { TraceLine } from "@/components/ui/trace";
import { TraceTitle } from "@/components/ui/trace";
import { TraceCollapsibleContent } from "@/components/ui/trace";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceDescription } from "@/components/ui/trace";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<Trace
><TraceCollapsible default-open>
<TraceCollapsibleTrigger
><TraceLine status="running"
><TraceTitle>Running: review sources</TraceTitle></TraceLine
></TraceCollapsibleTrigger
>
<TraceCollapsibleContent
><Trace>
<TraceCollapsible default-open
><TraceCollapsibleTrigger
><TraceLine
><TraceTitle>Complete: inspect files</TraceTitle></TraceLine
></TraceCollapsibleTrigger
><TraceCollapsibleContent
><Trace>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: read the request</TraceTitle
><TraceDescription>0.4 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Search" /></TraceIcon
><TraceTitle>Complete: searched four files</TraceTitle
><TraceDescription>1.2 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle
>Complete: prepared the answer</TraceTitle
></TraceLine
>
</Trace></TraceCollapsibleContent
></TraceCollapsible
>
<TraceLine status="pending"
><TraceTitle>Pending: write the report</TraceTitle></TraceLine
>
</Trace></TraceCollapsibleContent
>
</TraceCollapsible></Trace
>
</template>
Running Override
<script setup lang="ts">
import { ref } from "vue";
import { Trace } from "@/components/ui/trace";
import { TraceCollapsible } from "@/components/ui/trace";
import { TraceCollapsibleTrigger } from "@/components/ui/trace";
import { TraceLine } from "@/components/ui/trace";
import { TraceTitle } from "@/components/ui/trace";
import { TraceCollapsibleContent } from "@/components/ui/trace";
import { Button } from "@/components/ui/button";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
const running = ref(true);
const open = ref<boolean | undefined>();
</script>
<template>
<div style="display: grid; gap: 1rem; width: min(32rem, calc(100vw - 4rem))">
<Trace
><TraceCollapsible :open="open ?? running" @update:open="open = $event">
<TraceCollapsibleTrigger
><TraceLine :status="running ? 'running' : undefined"
><TraceTitle>{{
running ? "Running: inspect files" : "Complete: inspected files"
}}</TraceTitle></TraceLine
></TraceCollapsibleTrigger
>
<TraceCollapsibleContent
>Close this panel while the task runs. It stays closed when the task
state changes.</TraceCollapsibleContent
>
</TraceCollapsible></Trace
>
<Button variant="outline" @click="running = !running">{{
running ? "Finish task" : "Run task"
}}</Button>
<Button variant="ghost" @click="open = undefined">Reset user choice</Button>
</div>
</template>
Long Labels
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { TraceCollapsible } from "@/components/ui/trace";
import { TraceCollapsibleTrigger } from "@/components/ui/trace";
import { TraceLine } from "@/components/ui/trace";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceTitle } from "@/components/ui/trace";
import { TraceDescription } from "@/components/ui/trace";
import { TraceCollapsibleContent } from "@/components/ui/trace";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<div style="width: min(22rem, calc(100vw - 4rem))">
<Trace
><TraceCollapsible default-open>
<TraceCollapsibleTrigger
><TraceLine
><TraceIcon><Icon name="Search" /></TraceIcon
><TraceTitle
>Complete: searched every source file in the selected workspace
for the requested component</TraceTitle
><TraceDescription>12.5 s</TraceDescription></TraceLine
></TraceCollapsibleTrigger
>
<TraceCollapsibleContent
>src/features/reports/components/QuarterlyRevenueBreakdownChartWithExtraLongName.tsx</TraceCollapsibleContent
>
</TraceCollapsible></Trace
>
</div>
</template>
Link
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { TraceLine } from "@/components/ui/trace";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceTitle } from "@/components/ui/trace";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<Trace
><a href="#trace-source"
><TraceLine
><TraceIcon><Icon name="FileText" /></TraceIcon
><TraceTitle>Complete: read source</TraceTitle></TraceLine
></a
><span id="trace-source" class="text-neutral-strong"
>Source: local component files.</span
></Trace
>
</template>
In Dialog
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { Dialog } from "@/components/ui/dialog";
import { DialogTrigger } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { TraceLine } from "@/components/ui/trace";
import { TraceTitle } from "@/components/ui/trace";
import { DialogContent } from "@/components/ui/dialog";
import { DialogHeader } from "@/components/ui/dialog";
import { DialogTitle } from "@/components/ui/dialog";
import { DialogDescription } from "@/components/ui/dialog";
import { DialogBody } from "@/components/ui/dialog";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceDescription } from "@/components/ui/trace";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<Trace
><Dialog
><DialogTrigger as-child
><Button variant="ghost"
><TraceLine
><TraceTitle>Open trace in Dialog</TraceTitle></TraceLine
></Button
></DialogTrigger
><DialogContent
><DialogHeader
><DialogTitle>Task trace</DialogTitle
><DialogDescription
>Completed task steps.</DialogDescription
></DialogHeader
><DialogBody
><Trace>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: read the request</TraceTitle
><TraceDescription>0.4 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Search" /></TraceIcon
><TraceTitle>Complete: searched four files</TraceTitle
><TraceDescription>1.2 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: prepared the answer</TraceTitle></TraceLine
>
</Trace></DialogBody
></DialogContent
></Dialog
></Trace
>
</template>
In Sheet
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { Sheet } from "@/components/ui/sheet";
import { SheetTrigger } from "@/components/ui/sheet";
import { Button } from "@/components/ui/button";
import { TraceLine } from "@/components/ui/trace";
import { TraceTitle } from "@/components/ui/trace";
import { SheetContent } from "@/components/ui/sheet";
import { SheetHeader } from "@/components/ui/sheet";
import { SheetTitle } from "@/components/ui/sheet";
import { SheetDescription } from "@/components/ui/sheet";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceDescription } from "@/components/ui/trace";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<Trace
><Sheet
><SheetTrigger as-child
><Button variant="ghost"
><TraceLine
><TraceTitle>Open trace in Sheet</TraceTitle></TraceLine
></Button
></SheetTrigger
><SheetContent
><SheetHeader
><SheetTitle>Task trace</SheetTitle
><SheetDescription
>Completed task steps.</SheetDescription
></SheetHeader
><Trace>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: read the request</TraceTitle
><TraceDescription>0.4 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Search" /></TraceIcon
><TraceTitle>Complete: searched four files</TraceTitle
><TraceDescription>1.2 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: prepared the answer</TraceTitle></TraceLine
>
</Trace></SheetContent
></Sheet
></Trace
>
</template>
In Drawer
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { Drawer } from "@/components/ui/drawer";
import { DrawerTrigger } from "@/components/ui/drawer";
import { Button } from "@/components/ui/button";
import { TraceLine } from "@/components/ui/trace";
import { TraceTitle } from "@/components/ui/trace";
import { DrawerContent } from "@/components/ui/drawer";
import { DrawerHeader } from "@/components/ui/drawer";
import { DrawerTitle } from "@/components/ui/drawer";
import { DrawerDescription } from "@/components/ui/drawer";
import { DrawerBody } from "@/components/ui/drawer";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceDescription } from "@/components/ui/trace";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<Trace
><Drawer
><DrawerTrigger as-child
><Button variant="ghost"
><TraceLine
><TraceTitle>Open trace in Drawer</TraceTitle></TraceLine
></Button
></DrawerTrigger
><DrawerContent
><DrawerHeader
><DrawerTitle>Task trace</DrawerTitle
><DrawerDescription
>Completed task steps.</DrawerDescription
></DrawerHeader
><DrawerBody
><Trace>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: read the request</TraceTitle
><TraceDescription>0.4 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Search" /></TraceIcon
><TraceTitle>Complete: searched four files</TraceTitle
><TraceDescription>1.2 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: prepared the answer</TraceTitle></TraceLine
>
</Trace></DrawerBody
></DrawerContent
></Drawer
></Trace
>
</template>
In Popover
<script setup lang="ts">
import { Trace } from "@/components/ui/trace";
import { Popover } from "@/components/ui/popover";
import { PopoverTrigger } from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { TraceLine } from "@/components/ui/trace";
import { TraceTitle } from "@/components/ui/trace";
import { PopoverContent } from "@/components/ui/popover";
import { TraceIcon } from "@/components/ui/trace";
import { Icon } from "@/components/ui/icon";
import { TraceDescription } from "@/components/ui/trace";
const args = {
} satisfies Partial<
InstanceType<typeof Trace> extends { $props: infer Props } ? Props : {}
> &
Record<string, unknown>;
</script>
<template>
<Trace
><Popover
><PopoverTrigger as-child
><Button variant="ghost"
><TraceLine
><TraceTitle>Open trace in Popover</TraceTitle></TraceLine
></Button
></PopoverTrigger
><PopoverContent aria-label="Task trace"
><Trace>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: read the request</TraceTitle
><TraceDescription>0.4 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Search" /></TraceIcon
><TraceTitle>Complete: searched four files</TraceTitle
><TraceDescription>1.2 s</TraceDescription></TraceLine
>
<TraceLine
><TraceIcon><Icon name="Check" /></TraceIcon
><TraceTitle>Complete: prepared the answer</TraceTitle></TraceLine
>
</Trace></PopoverContent
></Popover
></Trace
>
</template>
API reference
Frontfriend-owned props. Native HTML and inherited primitive props
remain documented by Reka UI.
Trace
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
TraceCollapsible
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
defaultOpen | boolean | false | The initial open state. Bind it with :default-open. |
disabled | boolean | false | Disable changes through the trigger. |
open | boolean | — | The controlled open state. Bind it with v-model:open or handle update:open. |
update:open | (value: boolean) => void | — | Emitted when the open state changes. Used by v-model:open. |
TraceCollapsibleContent
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | Classes for the inner content wrapper. |
forceMount | boolean | false | Keep the content mounted when closed. Bind it with :force-mount. |
TraceCollapsibleTrigger
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
TraceDescription
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
TraceIcon
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
TraceLine
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
status | "running" | "error" | "pending" | — | The step status. Omit it for a normal or completed step. |
TraceTitle
| Prop | Type | Default | Description |
class | HTMLAttributes["class"] | — | |
Configuration determines the actual classes and available styling hooks.
See Theming & component configuration before introducing
a repeated local override.