StatusLabel

A two-line caption for the orb: the current voice state on top and a spaced-out brand mark below. Place it under the orb or the PushToTalkButton.

import { StatusLabel } from 'jarvis-react-ui';

States

state takes an AppOrbState and maps it to a built-in text. Every state except idle is shown in the bright accent color.

state Text
idle READY
listening listening...
thinking thinking...
speaking speaking...
follow_up follow-up...
working working...
import { StatusLabel } from 'jarvis-react-ui';
import type { AppOrbState } from 'jarvis-react-ui';

const STATES: AppOrbState[] = ['idle', 'listening', 'thinking', 'speaking', 'follow_up', 'working'];

export default function States() {
    return (
        <div className="grid grid-cols-2 gap-6 sm:grid-cols-3">
            {STATES.map((state) => (
                <div key={state} className="flex flex-col items-center gap-2">
                    <StatusLabel state={state} />
                    <code className="text-[9px] text-text-muted">{state}</code>
                </div>
            ))}
        </div>
    );
}

Custom texts and localization

labels overrides the text per state, for example to translate it. It is a partial map: states you leave out keep their built-in text.

import { StatusLabel } from 'jarvis-react-ui';
import type { AppOrbState } from 'jarvis-react-ui';

const GERMAN: Partial<Record<AppOrbState, string>> = {
    idle: 'BEREIT',
    listening: 'hört zu...',
    thinking: 'denkt nach...',
    speaking: 'spricht...',
    follow_up: 'Rückfrage...',
    working: 'arbeitet...',
};

export default function Localized() {
    return (
        <div className="flex gap-10">
            <StatusLabel state="idle" labels={GERMAN} />
            <StatusLabel state="thinking" labels={GERMAN} />
            <StatusLabel state="follow_up" labels={GERMAN} />
        </div>
    );
}

Custom brand

brand replaces the default J A R V I S mark. Spaces between the letters are part of the string; the component only adds letter spacing.

import { StatusLabel } from 'jarvis-react-ui';

export default function CustomBrand() {
    return <StatusLabel state="thinking" brand="F R I D A Y" />;
}

With the orb state

Feed StatusLabel the same state as your orb and pair it with WaveformMeters that run while audio flows. This demo cycles through the states on a timer; in an app the state comes from your voice pipeline. To switch states by hand while developing, use StateSimulator.

import { useEffect, useState } from 'react';
import { StatusLabel, WaveformMeter } from 'jarvis-react-ui';
import type { AppOrbState } from 'jarvis-react-ui';

const CYCLE: AppOrbState[] = ['idle', 'listening', 'thinking', 'speaking', 'follow_up', 'working'];

export default function OrbStateCycle() {
    const [index, setIndex] = useState(0);
    const state = CYCLE[index % CYCLE.length] ?? 'idle';
    const audible = state === 'listening' || state === 'speaking';

    useEffect(() => {
        const id = setInterval(() => setIndex((i) => i + 1), 1800);
        return () => clearInterval(id);
    }, []);

    return (
        <div className="flex items-center gap-6">
            <WaveformMeter active={audible} />
            <StatusLabel state={state} />
            <WaveformMeter active={audible} mirrored />
        </div>
    );
}

Announce state changes

Set live on the one StatusLabel that represents the assistant state. The status text becomes a polite live region, so screen readers announce each new state after the current speech:

<StatusLabel state={state} live />

The demos on this page leave live off, because the cycling demo would announce a change every couple of seconds.

Accessibility

  • By default the label is plain text and state changes are not announced. Set live to make the status text a polite live region (role="status", aria-live="polite"), so screen readers announce each new state without interrupting. Render only one live StatusLabel per screen, or every copy is announced.
  • It ignores pointer events (pointer-events: none), so it never blocks clicks on the orb behind it.

API

Prop Type Default Description
state (required) 'idle' | 'listening' | 'thinking' | 'speaking' | 'follow_up' | 'working' Current orb state; selects the status text (READY, listening..., ...) and highlights it in the accent color for every state except idle.
brand string J A R V I S Brand text shown in small, widely spaced letters below the status.
className string Extra classes for the root <div> element.
labels Partial<Record<AppOrbState, string>> Custom status texts per state, e.g. for localization; states you leave out keep their built-in text (READY, listening..., thinking..., speaking..., follow-up..., working...).
live boolean false Turns the status text into a polite live region (role="status", aria-live="polite"), so screen readers announce state changes.

Type AppOrbState

Full app-layer orb state — a superset of OrbState that includes states handled above the base state machine.

Components and hooks should use AppOrbState for their props / return values.

type AppOrbState = OrbState | 'working';

Type OrbState

States that drive the JARVIS orb visual and audio state machine. Single source of truth — copied from src/types.ts.

type OrbState = 'idle' | 'listening' | 'thinking' | 'speaking' | 'follow_up';