Panel

Panels are the framed surfaces of the HUD: a translucent glass body with corner brackets, side rails, a light trace and a header strip. They hold the content of a dashboard tile or a window.

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

Basic

A panel is as wide as its container and, without a set height, grows with its content. Size it with className (a class from your own CSS, or Tailwind utilities if your project uses Tailwind) or with style. With a fixed height the body scrolls when its content overflows. The body has 12px padding, so content such as Tabs needs no extra spacing.

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

export default function Basic() {
    return (
        <Panel title="Diagnostics" className="w-[280px] h-[120px]">
            <span className="text-text-secondary">All subsystems nominal.</span>
        </Panel>
    );
}

Header

The header shows an optional index glyph (ix), the title, three status dots, optional actions and an optional badge, in that order. Use IconButton for actions.

import { RefreshCw, Settings } from 'lucide-react';
import { IconButton, Metric, Panel } from 'jarvis-react-ui';

export default function Header() {
    return (
        <Panel
            ix="◈"
            title="System Vitals"
            badge="LIVE"
            actions={
                <>
                    <IconButton icon={RefreshCw} label="Refresh" size="sm" />
                    <IconButton icon={Settings} label="Settings" size="sm" />
                </>
            }
            className="w-[316px] h-[150px]"
        >
            <div className="grid grid-cols-2 gap-3">
                <Metric value={42} unit="%" />
                <Metric value={68} unit="°C" warn />
            </div>
        </Panel>
    );
}

Focus

focused switches the border to the accent color and turns on an animated bloom. The panel does not track focus itself: onFocus fires on mouse down anywhere inside it, so keep the focused id in state and pass it back.

import { useState } from 'react';
import { Panel } from 'jarvis-react-ui';

const PANELS = ['Transcript', 'Agenda', 'Now Playing'];

export default function Focus() {
    const [focused, setFocused] = useState('Transcript');

    return (
        <>
            {PANELS.map((title) => (
                <Panel
                    key={title}
                    title={title}
                    focused={focused === title}
                    onFocus={() => setFocused(title)}
                    className="w-[200px] h-[110px]"
                >
                    <span className="text-text-secondary">
                        {focused === title ? 'Focused' : 'Click to focus'}
                    </span>
                </Panel>
            ))}
        </>
    );
}

Note: Building windows

For draggable, slot-docked panels use WindowManager. Its windows are Panels wired through headerRef, onHeaderPointerDown and onHeaderClick for dragging and double-click docking. You rarely need these three props yourself.

Sound

Hovering a panel plays hover_panel through the nearest SfxProvider. Without a provider the panel stays silent. See Sound effects.

Accessibility

  • The panel is a presentational <div> without a landmark role. Wrap it in a <section> with an aria-label when the panel is a distinct region of the page.
  • focused is purely visual and does not move keyboard focus.
  • Header actions should be real buttons with accessible names, such as IconButton with label.

API

Prop Type Default Description
actions ReactNode Controls rendered in the header between the dots and the badge, e.g. icon buttons.
badge ReactNode Tag shown at the right end of the header, e.g. LIVE.
children ReactNode Panel body content.
className string Additional class names for the root element, e.g. width and height utilities.
focused boolean false Highlights the panel: accent border and a stronger, animated bloom.
headerRef Ref<HTMLDivElement> Ref to the header element, e.g. to measure it or attach a drag handle.
ix ReactNode Index glyph shown before the title in the header, e.g. ◈.
onFocus (() => void) Called on mouse down anywhere in the panel; use it to set focused.
onHeaderClick ((e: MouseEvent<HTMLDivElement, MouseEvent>) => void) Click handler on the header; used for double-click detection by Window.
onHeaderPointerDown PointerEventHandler<HTMLDivElement> Pointer-down handler on the header; used as a drag handle by Window.
style CSSProperties Inline style for the root element, e.g. { width: 320, height: 220 }.
title ReactNode Header title.