Prepared Docs

Prepared Docs

⌘K

    Loading navigation…

User

  1. Blocks
  2. Ai Elements
  3. API and Development

AI Elements

API and Development

View Source
Submit Issue

Chat assembles Conversation, Message, and PromptInput into a ready-made surface with one owner of spacing. Pass variant={ChatVariant.Default} (or omit variant) for bubbled user turns and a reflowing pill composer that floats over the transcript with a surface-colour scrim, or ChatVariant.Annotation for flat turns with a docked stacked (flush, divider-separated) composer in the annotation popover. Every chrome difference lives in CHAT_VARIANT_CHROME — including promptLayout (Reflow / Stacked), composerPlacement (Floating / Docked), and metaPlacement (Inline / Below) — do not scatter form-factor conditionals in consumers. Composer region padding is always zero; PromptInput owns its own layout insets.

Sizing and scrolling

Chat fills its parent and keeps the transcript as the only scroll region — the composer stays pinned in both form factors. Give the host a bounded height (a fixed height, a max-height, or a flex chain with min-height: 0); in an unbounded parent the transcript grows to its content height and never scrolls.

Empty Default chats with neither messages nor emptyState keep the composer in document flow (data-composer="docked") so content-sized hosts do not collapse around an absolutely positioned pill. As soon as a transcript or emptyState is present, Default floats the composer again. Annotation always docks the stacked composer, so empty Annotation chats stay in flow without that special case.

Chat props

NameTypeDefaultDescription
messagesChatMessage[]—Transcript in order; omit or pass [] for the empty state.
promptChatPromptrequiredComposer config (onSubmit, placeholder, attach, chips, suggestions, …). layout is owned by the variant.
variantChatVariantDefaultForm factor: default or annotation.
messageVariantMessageContentVariant—Overrides the variant's per-role bubble treatment, applying one treatment to every turn. Use it with showAuthor={false}, where the bubble is the only turn marker and the per-role split reads as an inconsistency.
statusPromptInputStatus"ready"Submission status. While "submitted" or "streaming", send is blocked; with prompt.onStop, the trailing control becomes a stop button.
emptyStateEmptyStateProps—Props passed through to EmptyState when there are no messages.
scrollToLatestLabelstring—Accessible label for the scroll-to-latest control.
classNamestring—Optional class merged onto the chat root.

ChatPrompt extras

NameTypeDescription
attachPromptInputAttachActionsShows the leading add control (images / files / …).
chipsPromptInputChip[]Persistent context chips above the typed area. See Context chips vs inline chips.
onChipDismiss(id: string) => voidFires when a context chip or an inlined chip is dismissed.
addLabelstringAccessible label for the add control.
onStop() => voidStops an in-flight generation. When set and status is "submitted" or "streaming", the trailing control becomes Secondary StopCircle.
stopLabelstringAccessible label for the stop control. Defaults to a localized "Stop generating".

Context chips vs inline chips

PromptInput has two chip surfaces, and they are not interchangeable.

chips (context row)insertChip (inline)
OwnershipDeclarative — pass the full set every renderImperative, via PromptInputHandle
PlacementOwn row above the typed areaInside the text flow, at the caret
In onSubmitNeverYes, as @label in message and a chip segment
Survives submitYesNo, the composer clears
Survives a controlled value changeYesNo, the editable is replaced

Use chips for pinned context the message applies to (tagged elements, files, records): the row mirrors the array exactly, so the owner's store stays the single source of truth and removal flows through onChipDismiss. Use insertChip only for chips that belong in the sentence, such as an accepted suggestion.

Do not drive chips from an imperative handle and a controlled value at once. Clearing on submit and replacing the editable on an external value change both destroy inline chips, which is what the context row exists to avoid.

Floating composer CSS custom properties

Declared on .ai-chat when composerPlacement is Floating (Default variant):

NameDefaultDescription
--ai-chat-composer-scrimvar(--color-background-base)Opaque surface colour the gradient fades into. Chat samples the nearest opaque parent background at runtime and writes an inline value on the chat root; that beats author rules targeting .ai-chat. To force a colour, set the variable on a child of the root (or clear the inline property). The CSS default is the fallback when no opaque parent is found.
--ai-chat-composer-heightmeasuredPublished by Chat via ResizeObserver; used for transcript bottom padding and lifting the scroll-to-latest control.

ChatMessage

NameTypeDescription
idstringStable list key.
fromMessageRoleAuthor role (user / assistant / …).
authorMessageAuthorDisplay name and optional avatar (src image URL wins over icon glyph). Demo Ally photo: ALLY_GORITHM_AVATAR_SRC.
metaReactNodeTurn metadata (timestamp, "Worked for 5m 26s"). CHAT_VARIANT_CHROME decides whether it trails the author name (MessageMetaPlacement.Inline, used by Default) or stacks beneath it (MessageMetaPlacement.Below, used by Annotation). With showAuthor={false} there is no author row to place it in, so Message renders it as a caption beneath the body instead and metaPlacement does not apply.
textstringMarkdown sugar via Response when content is absent.
streamingbooleanMarks text as a live token stream.
contentReactNodeRich turn body; wins over text.

Import

Default form factor

Narrow Default (full-screen chrome at popover width)

Annotation form factor

CodeBlock

CodeBlock from @prepared911/ui-ai-elements renders a fenced code surface with a language label, optional copy control, and Shiki highlighting using github-light / github-dark-dimmed (same themes as the design docs site). Dark is the default token color; light theme switches via .light / .light-theme ancestors from ThemeProvider.

Props

NameTypeDefaultDescription
codestringrequiredRaw source to display and copy.
languagestring—Header label and Shiki language id (aliases like ts → typescript are normalized).
showCopybooleantrueWhen false, hides the copy IconButton.
classNamestring—Optional class merged onto the root.

Import

TypeScript sample

JSON sample

Without copy

Related

  • Response maps markdown fenced code nodes to CodeBlock.
  • Tool stringifies input/output and renders them with language="json".
  • Chat owns transcript + composer spacing for both form factors.

Shimmer

Shimmer is an animated in-progress label (e.g. "Thinking…" / "Reasoning"). A highlight sweeps across the glyphs via a clipped gradient; when an optional leading icon is provided, its fill sweeps in phase with the text. When active is false it renders as plain muted text. Respects prefers-reduced-motion.

Active and icon paths root in FlexBox (a div). Prefer placing Shimmer in flex/block parents, not inside a paragraph.

Props

NameTypeDefaultDescription
typeTextTypeBodySmallTypography variant for the text.
activebooleantrueWhen true, animates a highlight sweeping across the text and icon.
asSpanbooleantrueWhen true, the active/icon root uses display: inline-flex and the label text renders as a span. The root itself is still a div — do not nest inside a <p>. When inactive with no icon, the control collapses to a CoreText span.
iconSVGAsset—Optional leading icon; fill sweeps in phase with the text.
classNamestring—Optional class merged onto the root.

Import

Active with icon

Inactive

Previous

AI Elements / Usage

Next

AI Elements / Accessibility

On this page

Sizing and scrolling
Chat props
ChatPrompt extras
Context chips vs inline chips
Floating composer CSS custom properties
ChatMessage
Import
Default form factor
Narrow Default (full-screen chrome at popover width)
Annotation form factor
Props
Import
TypeScript sample
JSON sample
Without copy
Related
Props
Import
Active with icon
Inactive