AI components

Reasoning

Show an assistant's progress in a collapsible section.

Installation

pnpm dlx @mielui/svelte add reasoning

Usage

Reasoning starts open. Set open={false} for a collapsed summary, or bind open to control it from the parent. Trigger shows its title only while collapsed.

Set streaming while the model is thinking; the label reads Thinking and shimmers. Clear it when delivery finishes and pass duration to read Thought for 2.4s. Write a short, user-facing account of the work rather than exposing private model reasoning.

<script lang="ts">
    import * as Reasoning from '@mielui/svelte/components/reasoning';
</script>

<Reasoning.Root>
    <Reasoning.Trigger title="Searched the release history" duration="2.4s" />
    <Reasoning.Content>
        <p>Compared the incident timestamp with the last five deployments.</p>
    </Reasoning.Content>
</Reasoning.Root>

Examples

Live reasoning

streaming stays on while ResponseStream writes the trace and clears in its onComplete.

Open events

onOpenChange runs when the reasoning opens or closes. onOpenChangeComplete runs after the animation has finished, which is the moment to measure or scroll.

Parts

Root and Content render their children and accept class and other element attributes. Trigger takes title and duration; pass children to replace its whole label, which receives open and streaming.

Labels

Built-in text is English by default. Pass a labels object of type ReasoningLabels to Reasoning.Root to reword the trigger while streaming and after it completes. thought is the status line without a duration; thoughtFor receives the duration and returns the whole line when there is one. title is the summary shown while closed when Trigger has no title. Every key is optional; omitted keys keep their default.

<script lang="ts">
    import * as Reasoning from '@mielui/svelte/components/reasoning';
    import type { ReasoningLabels } from '@mielui/svelte/components/reasoning';

    let { streaming }: { streaming: boolean } = $props();

    const labels: ReasoningLabels = {
        thinking: 'Rรฉflexion',
        thought: 'Rรฉflexion terminรฉe',
        thoughtFor: (duration) => `Rรฉflexion de ${duration}`,
        title: 'Brouillon'
    };
</script>

<Reasoning.Root {streaming} {labels}>
    <Reasoning.Trigger duration="2.4s" />
    <Reasoning.Content>โ€ฆ</Reasoning.Content>
</Reasoning.Root>

API reference

Reasoning.Root

Controls reasoning visibility.

  • labels
    ReasoningLabels

    Overrides the built-in text and accessible names. Every key is optional and English is the fallback.

  • streaming
    boolean

    Marks the reasoning as still being written.

    Default false

  • open Bindable
    boolean

    Whether the reasoning content is visible.

    Default true

  • onOpenChange
    ((open: boolean) => void)

    Called with the new state whenever it opens or closes.

  • onOpenChangeComplete
    ((open: boolean) => void)

    Called after the open or close animation finishes.

  • children
    Snippet<[]>

    Content rendered inside.

  • class
    (string & (ClassValue | null))

    Classes added to the element.

Reasoning.Content

Contains reasoning content.

  • class
    (string & (ClassValue | null))

    Classes added to the element.

  • children
    Snippet<[]>

    Content rendered inside.

Reasoning.Trigger

Toggles reasoning content.

  • title
    string

    Summary shown under the status line while the reasoning is closed.

  • duration
    string

    A compact summary of the completed reasoning time, such as 2.4s.

  • children
    Snippet<[Readonly<{ open: boolean; streaming: boolean; }>]>

    Content rendered inside.

  • class
    (string & (ClassValue | null))

    Classes added to the element.