Prompt Bar

A composer where @ adds a source, / runs a command and a menu picks the model.

Type @ to add a source. Type / to run a command.

Try typing @ or /

'use client';

import { useState } from 'react';
import { PromptBar } from '@brand-studio/ui';
import type { PromptSubmission } from '@brand-studio/ui';

export default function PromptBarDemo() {
  const [last, setLast] = useState<PromptSubmission>();
  return (
    <div style={{ width: '100%', maxWidth: 600, display: 'grid', gap: 16, paddingTop: 180 }}>
      <PromptBar
        sources={[
          { id: 'roasts', label: 'Roast log', hint: 'Sheet' },
          { id: 'notes', label: 'Tasting notes', hint: 'Doc' },
          { id: 'supplier', label: 'Supplier prices', hint: 'Sheet' },
          { id: 'orders', label: 'Open orders', hint: 'Shop' },
        ]}
        commands={[
          { id: 'summarise', label: 'summarise', hint: 'Short summary' },
          { id: 'reorder', label: 'reorder', hint: 'Draft a purchase order' },
          { id: 'email', label: 'email', hint: 'Write to a customer' },
        ]}
        models={[{ value: 'fast', label: 'Fast' }, { value: 'deep', label: 'Deep thinking' }]}
        onSubmit={setLast}
      />
      <p style={{ margin: 0, minHeight: 24, color: 'var(--bs-muted)', fontSize: 14 }}>
        {last ? `${last.command ? `/${last.command} ` : ''}${last.text}${last.sources.length ? ` · sources: ${last.sources.join(', ')}` : ''} · ${last.model}` : 'Try typing @ or /'}
      </p>
    </div>
  );
}

Installation

pnpm add @brand-studio/ui

Usage

import { PromptBar } from '@brand-studio/ui';
<PromptBar
  sources={[{ id: 'roasts', label: 'Roast log', hint: 'Sheet' }]}
  commands={[{ id: 'summarise', label: 'summarise' }]}
  models={[{ value: 'fast', label: 'Fast' }, { value: 'deep', label: 'Deep thinking' }]}
  onSubmit={({ text, sources, command, model }) => ask(text, { sources, command, model })}
/>

Type @ anywhere to add a source, or / at the very start for a command. A list opens above the text and narrows as you type. Arrow keys move, Enter or Tab picks, and Escape closes the list. Picks become chips above the text; Backspace in an empty box removes the last one. On send, a band of light crosses the bar once.

Leave room above the bar for the list.

Accessibility

  • The text box points at the open list and its highlighted option, so screen readers follow the arrow keys without leaving the text.
  • A status line announces how many sources or commands match, and a description tells people that @ and / exist.
  • Each chip has a labelled remove button. The model menu is a labelled menu button.

API Reference

PropTypeDefault
sources?PromptOption[]
commands?PromptOption[]
models?PromptModel[]
model?string
onModelChange?((value: string) => void)
onSubmit?((prompt: PromptSubmission) => void)
onStop?(() => void)
busy?booleanfalse
label?string'Prompt'
placeholder?string'Ask anything. @ adds a source, / runs a command'
start?React.ReactNode
className?string''

Still, Deskhand and Hollis are fictional brands. The coffee photographs are original generated artwork. @brand-studio/ui is MIT licensed.