@elabs-ai/components-ai
v6.1.0
Published
<!-- brand-ui:gen:readme:start --> <!-- Generated by scripts/gen-package-readmes.mjs — do not edit inside these markers. -->
Readme
@elabs-ai/components-ai
ChatShell, Conversation, Message, PromptInput, Tool, Reasoning, citations.
Part of brand-ui, a source-owned, token-driven React component system.
Published to the public npm registry under the @elabs-ai scope — it
installs like any other npm dependency, with no registry configuration and
no token required. See docs/CONSUMING.md.
Install
pnpm add @elabs-ai/components-tokens @elabs-ai/components-aiSet up styling (do not skip)
Components are Tailwind v4 classes backed by semantic tokens. Two lines in your CSS entry, or everything renders unstyled — the single most common mistake:
@import "@elabs-ai/components-tokens/styles.css";
@source "../node_modules/@elabs-ai/components-ai/dist";The @source line is required because Tailwind ignores node_modules. Add
one per brand-ui package you render. Then wrap your app once:
import { ThemeProvider } from "@elabs-ai/components-tokens";
<ThemeProvider defaultTheme="light">{children}</ThemeProvider>;This package specifically
ai(Vercel AI SDK) is a types-only, optional peer — your app owns the model calls.@xyflow/reactis a peer too (required), if you render the agent canvas.mermaid,@rive-app/react-webgl2and@xterm/xterm+@xterm/addon-fitare optional peers reached only through a lazyimport()(ADR 0019) — see "Only install what you render" below.
What's in it
449 exported components — including A2UI_CATALOG_SCHEMA, A2UI_CATALOG_VERSION, A2UI_COMMON_PROPS, A2UI_SURFACE_SCHEMA_ID, A2UI_VERSION.
Don't guess the API — ask the CLI:
pnpm add -D @elabs-ai/components-cli
pnpm exec brand-ui search <query> # find a component
pnpm exec brand-ui docs <Name> # its real props, from sourceUsing an AI coding agent?
For Claude Code, install the plugin from this repo's checkout:
/plugin marketplace add .
/plugin install brand-uibrand-ui docs <Name> returns intent, composition, state→token mappings and
anti-patterns — tell your agent to run it instead of guessing a prop. The CLI
also runs as an MCP server (brand-ui mcp).
Full guide
Tailwind and Next.js wiring, per-package extras, agent enablement and a
prompt for migrating an existing project: docs/CONSUMING.md.
License
MIT
Only install what you render
Five peers are optional. The package installs and builds with none of them —
each is reached only through a lazy import() (ADR 0019), and a feature whose
peer is absent renders an actionable message naming the package to install,
never a blank component or an unhandled rejection (ADR
0032).
| Peer | Unlocks |
| ----------------------------------- | ----------------------------------------------------------- |
| mermaid | Mermaid diagrams in streamed markdown |
| @rive-app/react-webgl2 | Persona's animated avatar |
| @xterm/xterm + @xterm/addon-fit | InteractiveTerminal |
| ai | Types for the Vercel AI SDK's UIMessage — no runtime cost |
pnpm add mermaid
pnpm add @rive-app/react-webgl2
pnpm add @xterm/xterm @xterm/addon-fit
pnpm add ai@xyflow/react (the agent-canvas set) stays a required peer — install it
whenever you import from this package.
Known limitation: mermaid's bytes are always installed, even when you
skip the peer — two of this package's own plain dependencies (not of
your app), streamdown and @streamdown/mermaid, each declare mermaid as
their own plain, non-optional dependency, so every package manager resolves
it regardless of what your app's manifest says. A hoisting layout
additionally makes import("mermaid") resolve, so the runtime capability-gap
panel never renders for you; skipping the peer still means you never have to
declare mermaid yourself, and a genuinely unresolved engine still fails
actionably rather than crashing. pnpm check --rule optional-peer-transitives (issue #94)
tracks this as a defeated optional peer and will fail the day it is fixed
upstream.
Full detail (exact peer version ranges, per-feature notes):
docs/CONSUMING.md §6.
Package detail
Presentational AI/chat components — ChatShell, Conversation, Message,
PromptInput/Composer, Tool, Reasoning, Sources, Artifact,
ContextPanel, and the workspace/agent set.
Composer is the chat input. Every control the PromptInput family ships is
reachable from a Composer prop; drop to PromptInput only for a bespoke
shell. The slots: modelPicker (pass a ModelPicker from
@elabs-ai/components-ui), mode (PromptInputMode), effort
(PromptInputEffort) and slashCommands (PromptInputSlash). The footer order
is attach · modelPicker · mode · effort │ voice · send, matching
TerminalComposer so the chat and console skins agree.
The components render the AI SDK UIMessage data model. Your app owns the model
calls (useChat, transport, providers) — @elabs-ai/components-ai imports the ai SDK as
types only, never at runtime (D6 / ADR-0008). See docs/DECISIONS.md §D5.
Usage, props and composition patterns live in Storybook and
docs/component-inventory.md. This file covers only what you need to know when
deploying it.
Network egress
Two components reach third-party origins at runtime, and several link out. Under a restrictive CSP these fail — usually silently.
| What | Origin | Directive | Escape hatch |
| ---------------------------------- | ------------------------------------------------------------- | ----------------- | --------------------------------------------------------------- |
| ModelProviderLogo provider logos | models.dev | img-src | src for a self-hosted asset, or fallback |
| Persona Rive artwork | *.public.blob.vercel-storage.com | connect-src | self-host and pass src; blocked loads render a fallback orb |
| OpenIn* deep links | chatgpt.com, claude.ai, cursor.com, scira.ai, t3.chat, v0.app | none (navigation) | don't render the component — note the prompt travels in the URL |
Full detail, the exact CSP snippet, and the offline checklist:
docs/CSP-AND-NETWORK.md.
Trusted Types
Under require-trusted-types-for 'script', two transitive markdown dependencies
resolve to innerHTML/DOMParser builds and blank content (a message containing
& renders empty), and Mermaid's DOMPurify installs a pass-through policy
named dompurify.
A library cannot fix this for you — it is export-condition selection in your
bundler. The copy-pasteable alias snippet and the CSP directives are in
docs/CSP-AND-NETWORK.md §2, and this repo
dogfoods them in apps/playground and apps/docs.
Bundle size
Heavy engines load on demand rather than riding in your entry chunk:
- Mermaid (plus d3 and DOMPurify) loads on the first diagram render. Call
preloadMermaid()to warm it early on a surface you know renders diagrams. - The Rive WebGL2 runtime loads only when a
Personamounts.
Both are enforced by pnpm check --rule eager-heavy-deps. See ADR 0019. The remaining eager
engines (React Flow, xterm) are tracked in that gate's baseline
(the React Flow canvas set is a separate, intentional surface — see ADR 0018).
