Skip to content
Get started

Components

PromptComposer

Unstable: where people write to the assistant, a textarea that grows with the text, tools at the start and a send button at the end. Enter sends, Shift+Enter adds a line. Import it from @nizivo/react/unstable/prompt-composer.

Tier: clientUnstable

Examples

Basic

The composer: attach and dictate at the start, send at the end once there is text.

import type { JSX } from 'react';
import { IconButton } from '@nizivo/react/icon-button';
import { PromptComposer } from '@nizivo/react/unstable/prompt-composer';

/** Stand-ins for `@nizivo/icons` glyphs (Lucide strokes). */
function Paperclip(): JSX.Element {
  return (
    <svg
      viewBox="0 0 24 24"
      width="1em"
      height="1em"
      fill="none"
      stroke="currentColor"
      strokeWidth={1.92}
      strokeLinecap="round"
      strokeLinejoin="round"
    >
      <path d="m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551" />
    </svg>
  );
}

function Mic(): JSX.Element {
  return (
    <svg
      viewBox="0 0 24 24"
      width="1em"
      height="1em"
      fill="none"
      stroke="currentColor"
      strokeWidth={1.92}
      strokeLinecap="round"
      strokeLinejoin="round"
    >
      <path d="M12 19v3" />
      <path d="M19 10v2a7 7 0 0 1-14 0v-2" />
      <rect x="9" y="2" width="6" height="13" rx="3" />
    </svg>
  );
}

export function PromptComposerExample(): JSX.Element {
  return (
    <PromptComposer
      style={{ maxInlineSize: 640 }}
      labels={{ placeholder: 'Ask Nizivo AI anything…' }}
      tools={
        <>
          <IconButton variant="secondary" size="sm" label="Attach file" icon={<Paperclip />} />
          <IconButton variant="secondary" size="sm" label="Dictate" icon={<Mic />} />
        </>
      }
    />
  );
}

Draft

With a draft: the send button is enabled.

import type { JSX } from 'react';
import { PromptComposer } from '@nizivo/react/unstable/prompt-composer';

export function PromptComposerDraftExample(): JSX.Element {
  return (
    <PromptComposer
      style={{ maxInlineSize: 640 }}
      defaultValue="Which products sold out last week?"
    />
  );
}

Import

import { PromptComposer } from '@nizivo/react/unstable/prompt-composer';

// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css
import '@nizivo/react/css/prompt-composer.css';

Static or interactive

Client. It holds the text and sends on Enter. How to choose.

Text and sending

value, defaultValue and onValueChange hold the text; onSend gets it on Enter or the send button, unless it is only spaces, and an uncontrolled composer clears after. Shift+Enter adds a line, and Enter while an input method is composing does neither. pending keeps the send button disabled while an answer is on its way; the text stays editable. The composer is a <form>, so name posts the text with it.

Tools

tools sits at the start of the toolbar: IconButtons that attach or dictate ("Attach file", "Dictate"), a ModelSelector.

Accessibility

The textarea is named by a hidden label ("Message"); the placeholder is a hint, not its name. It grows with the text, to 12 lines, where the browser has field-sizing. The send button stays focusable while there is nothing to send, marked aria-disabled.

Props

Client component Renders data-slot="prompt-composer" with the class nz-prompt-composer. Props: PromptComposerProps. Source: src/unstable/prompt-composer/prompt-composer.client.tsx.

NameTypeDefaultDescription
defaultValuestring''

The text at first (uncontrolled).

disabledboolean–
labelsPartial<PromptComposerLabels>–
namestring–

The textarea's name, for a form that posts it.

onSend(value: string) => void–

Enter or the send button, with text that is not only spaces. Uncontrolled, the text clears after.

onValueChange(value: string) => void–
pendingbooleanfalse

An answer is on its way: the send button is disabled; the text stays editable.

renderRenderProp<PromptComposerState>–

Must render a <form>.

toolsReactNode–

Left of the send button: IconButtons that attach or dictate, a ModelSelector.

valuestring–

The text (controlled).

  • Also takes every attribute of <form> except children, defaultValue, onSubmit; name is redeclared above. (Omit<ComponentPropsWithRef<"form">, "onSubmit" | "children" | "defaultValue">)

render takes an element, or, in client code, a function of the props and this state (PromptComposerState):

NameTypeDefaultDescription
emptyrequiredboolean–
pendingrequiredboolean–

Other exports

PromptComposerLabels type

import type { PromptComposerLabels } from '@nizivo/react/unstable/prompt-composer'

PromptComposer's own strings (§16.4): serialisable, English defaults.

NameTypeDefaultDescription
labelrequiredstring'Message'

The textarea's name.

placeholderrequiredstring'Ask anything…'
sendrequiredstring'Send'

The send button's name.

PromptComposerProps type

import type { PromptComposerProps } from '@nizivo/react/unstable/prompt-composer'

The props of PromptComposer, listed above.

PromptComposerState type

import type { PromptComposerState } from '@nizivo/react/unstable/prompt-composer'

The render state of PromptComposer, listed above.

Data attributes and slots

Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.

SlotRendered byData attributes
prompt-composer
.nz-prompt-composer
PromptComposer
root (takes render)
  • data-disabled (present or absent) ← disabled
    Mirrors the disabled attribute
prompt-composer-input
.nz-prompt-composer-input
PromptComposer
inner element (CSS only); interactive, focus: self
none
prompt-composer-send
.nz-prompt-composer-send
PromptComposer
inner element (CSS only); interactive, focus: self
none

CSS hooks

Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.

This stylesheet reads no public hook.

Layers: nz.components. Classes: .nz-prompt-composer, .nz-prompt-composer-input, .nz-prompt-composer-send, .nz-prompt-composer-toolbar, .nz-prompt-composer-tools.

Tokens this stylesheet reads (23)

--nz-bg-brand, --nz-bg-brand-hover, --nz-bg-disabled, --nz-bg-surface, --nz-border-control, --nz-border-focus, --nz-border-width-default, --nz-border-width-focus, --nz-duration-fast, --nz-easing-standard, --nz-elevation-2, --nz-font-body-l, --nz-radius-full, --nz-radius-xl, --nz-space-1, --nz-space-2, --nz-space-3, --nz-space-4, --nz-space-8, --nz-text-disabled, --nz-text-on-brand, --nz-text-primary, --nz-text-tertiary

Accessibility

These parts are interactive. Each gets the focus outline and touch-action rule from @nizivo/react/css/base.css (the nz.base layer), so the floor survives a restyle:

  • prompt-composer-input: draws the focus outline itself on keyboard focus.
  • prompt-composer-send: draws the focus outline itself on keyboard focus.

Keyboard

To be written.

On this page