Standard catalog

Use the 69 standard components, drop the ones you do not want, and replace any of them with your own.

Open your coding agent in your project's folder, or in an empty folder for a new app.This runs in a coding agent on your computer.

What is this?#

You want the agent to answer with tables, charts, and forms today, not after you build a component library. standardUI is a catalog of 69 ready-made components that the agent already knows how to use. The 18 components of the A2UI 1.0 basic catalog are in it under their A2UI names and props (Image.url, CheckBox.value, Row.justify: "spaceBetween", weight for flex-grow); the rest extend the catalog.

Use it as it is:

import { standardUI } from "@copilotkit/react-core/v2/generative-ui";

<CopilotKitProvider runtimeUrl="/api/copilotkit" generativeUI={{ ui: standardUI }}>

What is in it#

GroupComponents
LayoutBox, Column, Row, Grid, GridItem, Card, Flow, FlowItem, Carousel, CarouselItem, CarouselMediaItem, Spacer, Divider, Tabs
TextTitle, Text, Caption, Label, Bold, Italic, Underline, Strikethrough, Badge, Blockquote, Code, Markdown, Math, ShimmerText, Link, Tooltip
InputsButton, Pressable, Form, TextField, TextArea, Select, CheckBox, Radio, RadioGroup, Slider, SegmentedControl, ChoicePicker, DateTimeInput
DataTable, TableSection, TableRow, TableCell, List, ListItem, Chart, Map
MediaImage, Icon, Favicon, Svg, Video, AudioPlayer, HtmlView
Feedback and overlayPulseIndicator, FlashcardFlip, Popover, PopoverTrigger, PopoverContent, Modal
CompositesLinkCard, Citation, FollowUp, EntityCard, ImageGrid

A few things to know:

  • Every input validates. checks holds the Checkable rules of A2UI 1.0: [{ "condition": { "@call": "email", "args": { "value": { "@path": "/form/email" } } }, "message": "Enter a valid email" }]. An input shows the first failed message once the user has been in it, and a Button with the same checks is disabled while one fails. A result carries the A2UI ValidationResult fields: the built-in validators set a code (required, pattern, tooShort, tooLong, notANumber, tooSmall, tooLarge, email), and a severity of "warning" or "info" (from a bound result or your own validator) shows the message in its own colour without making the input invalid or holding the Button back.
  • Video takes any URL. A video file plays in the native player, with captions as WebVTT tracks; a YouTube link shows a poster until the user presses play, then loads the privacy-enhanced embed. A page on another video site (Vimeo, Loom, TikTok, …) and a file that fails to load show a link card instead of a dead player. YouTube is the only provider that embeds; to embed another one, replace the component. Tabs takes tabs: [{ "title", "child" }] with the id of each panel.
  • Inputs keep what users type. When the agent binds an input to a value, what the user types stays. A later agent update cannot write over it.
  • Button and Pressable can act in the browser. href opens a URL, and Button with copy copies text, with no message to the agent.
  • Map needs one package. Run npm install maplibre-gl if your agent draws maps. Without it, the map shows a list of the places.
  • Chart works out of the box. It uses recharts, which comes with CopilotKit.

To see every component with sample data, run examples/v2/a2ui-markdown and open /catalog.

Express calling conventions#

The standard catalog exports content, children, labels/values and common actions before presentation parameters. For example, the short prefixes are Text(text?, children?), Column(children?), Button(label?, onClick?), TextField(label?, value?) and Chart(data?, xKey?, series?, chartType?). Other component-specific fields follow, then shared layout and typography fields. Optional styling is easiest to pass by name.

This is CopilotKit's catalog design, not a prescribed list of signatures from A2UI. The official Express specification defines how JSON property order becomes argument order. The standard catalog applies that rule through exportA2UICatalog, so agents consuming the exported catalog receive the same calling convention regardless of framework.

Compared with the initial experimental style-first catalog, this changes positional meanings. Start a fresh conversation when moving to this catalog and regenerate saved positional Express source against its signatures. Named arguments and JSON property values keep their meaning.

Add your own components#

Put your components on top of the standard ones with extends:

import { createGenerativeUI, standardUI } from "@copilotkit/react-core/v2/generative-ui";

export const appUI = createGenerativeUI({
  id: "acme/app@1",
  extends: [standardUI],
  components: {
    ProductCard: { component: ProductCard, props: productSchema },
  },
});

See Catalogs for how to declare a component.

Drop components#

Every component makes the prompt a little longer. If your app never needs a map or a video, remove them. omit returns a copy of the catalog without them, and the agent no longer sees them:

export const appUI = createGenerativeUI({
  id: "acme/app@1",
  extends: [standardUI.omit(["Map", "Video", "HtmlView"])],
  components: {},
});

The names are typed, so a typo is a type error. Call omit once, at module level.

Replace a component#

Your app has its own card, with your shadows and spacing. overrides swaps the React component of a standard component. The agent sees the same component as before, with the same props:

import {
  createGenerativeUI,
  standardUI,
  type GenerativeUIComponentProps,
} from "@copilotkit/react-core/v2/generative-ui";

function MyCard({ children }: GenerativeUIComponentProps<typeof standardUI, "Card">) {
  return <div className="rounded-2xl border p-6 shadow-sm">{children}</div>;
}

export const appUI = createGenerativeUI({
  id: "acme/app@1",
  extends: [standardUI],
  overrides: { Card: { component: MyCard } },
  components: {},
});
  • Your component gets the props of the component it replaces. The types check this.
  • Only components of the catalogs in extends can be overridden. An unknown name is a type error.
  • You can combine both: extends: [standardUI.omit(["Map"])] with overrides: { Card: ... }.

Next: make the standard components match your brand with a theme.