# Reasoning

Expandable model reasoning status and trace for AI responses. Its trigger shares the disclosure row: ghost hover fill, rounded focus ring, and a trailing chevron.

- Package: `@mielui/svelte`
- Component version: `1.2.0`
- Depends on Mielui components: _internal/utils, _internal/disclosure, button
- Shared utilities: components/_internal/button-attributes, hugeicons-icon, utils.cn, utils.createContext, transition

## Install

~~~~sh
pnpm dlx @mielui/svelte add reasoning
~~~~

## API

This reference is generated at build time from the component manifest, public `index.ts`, and documentation examples below. Changes to those source files are reflected here in the published Markdown. Standard Svelte and HTML attributes accepted by the exported prop types are supported.


### Content

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| class | (string & (ClassValue \| null)) \| undefined | - | No | No | Classes added to the element. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Root

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| labels | ReasoningLabels \| undefined | - | No | No | Overrides the built-in text and accessible names. Every key is optional and English is the fallback. |
| streaming | boolean \| undefined | false | No | No | Marks the reasoning as still being written. |
| open | boolean \| undefined | true | No | Yes | Whether the reasoning content is visible. |
| onOpenChange | ((open: boolean) => void) \| undefined | - | No | No | Called with the new state whenever it opens or closes. |
| onOpenChangeComplete | ((open: boolean) => void) \| undefined | - | No | No | Called after the open or close animation finishes. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| class | (string & (ClassValue \| null)) \| undefined | - | No | No | Classes added to the element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Trigger

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| title | string \| undefined | - | No | No | Summary shown under the status line while the reasoning is closed. |
| duration | string \| undefined | - | No | No | A compact summary of the completed reasoning time, such as 2.4s. |
| children | Snippet<[Readonly<{ open: boolean; streaming: boolean; }>]> \| undefined | - | No | No | Content rendered inside. |
| class | (string & (ClassValue \| null)) \| undefined | - | No | No | Classes added to the element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Public types

~~~~ts
import type { DefaultProps } from '@mielui/svelte/utils';
import type { Snippet } from 'svelte';
import type { HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
import Root from './reasoning.svelte';
import Content from './reasoning-content.svelte';
import Trigger from './reasoning-trigger.svelte';

export type ReasoningLabels = {
    /** Status line while the reasoning is streaming. */
    thinking?: string;
    /** Status line once the reasoning finishes without a `duration`. */
    thought?: string;
    /** Status line once the reasoning finishes with a `duration`, such as "Thought for 2.4s". */
    thoughtFor?: (duration: string) => string;
    /** Summary under the status line while closed when the trigger has no `title`. */
    title?: string;
};

export type ReasoningRootProps = {
    /**
     * Overrides the built-in text and accessible names. Every key is optional and English is the
     * fallback.
     */
    labels?: ReasoningLabels;
    /** Marks the reasoning as still being written. */
    streaming?: boolean;
    /** Whether the reasoning content is visible. */
    open?: boolean;
    /** Called with the new state whenever it opens or closes. */
    onOpenChange?: (open: boolean) => void;
    /** Called after the open or close animation finishes. */
    onOpenChangeComplete?: (open: boolean) => void;
    /** Content rendered inside. */
    children?: Snippet;
} & Omit<DefaultProps, 'children'> &
    Omit<HTMLAttributes<HTMLElement>, 'children'>;

export type ReasoningTriggerProps = {
    /** Summary shown under the status line while the reasoning is closed. */
    title?: string;
    /** A compact summary of the completed reasoning time, such as 2.4s. */
    duration?: string;
    /** Content rendered inside. */
    children?: Snippet<[ReasoningTriggerState]>;
} & Omit<DefaultProps, 'children'> &
    Omit<HTMLButtonAttributes, 'children' | 'onclick' | 'title'>;

export type ReasoningTriggerState = Readonly<{
    open: boolean;
    streaming: boolean;
}>;

export type ReasoningContentProps = DefaultProps &
    Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'id'>;

export { Content, Root, Trigger };
~~~~

## Examples

### Events

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

    let state = $state('open');
</script>

<div class="flex w-full max-w-md flex-col gap-3">
    <Reasoning.Root
        onOpenChange={(open) => {
            state = open ? 'opening' : 'closing';
        }}
        onOpenChangeComplete={(open) => {
            state = open ? 'open' : 'closed';
        }}
    >
        <Reasoning.Trigger title="Compared the two plans" duration="3s" />
        <Reasoning.Content>
            <p>
                Yearly billing is cheaper after the eighth month, so it wins for a team that stays.
            </p>
        </Reasoning.Content>
    </Reasoning.Root>
    <p class="text-sm text-foreground-muted">The reasoning is {state}.</p>
</div>
~~~~

### Streaming

~~~~svelte
<script lang="ts">
    import * as Reasoning from '@mielui/svelte/components/reasoning';
    import { ResponseStream } from '@mielui/svelte/components/response-stream';

    const trace =
        'Checking the release history, recent errors, and payment-provider status against the incident timeline.';

    let streaming = $state(true);
</script>

<Reasoning.Root class="w-full max-w-xl" {streaming}>
    <Reasoning.Trigger />
    <Reasoning.Content>
        <ResponseStream
            textStream={trace}
            speed={45}
            onComplete={() => {
                streaming = false;
            }}
            class="text-foreground-muted"
        />
    </Reasoning.Content>
</Reasoning.Root>
~~~~

For the rendered reference, visit [/docs/components/reasoning](/docs/components/reasoning).
