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.

React Native

The standard components render DOM, so React Native has no standardUI yet. Build a catalog of your own native components with createGenerativeUI; see Catalogs and Generative UI with your own components.

Use it as it is:

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

<CopilotKitProvider runtimeUrl="/api/copilotkit" generativeUI={{ ui: standardUI }}>
src/app/app.config.ts
import { provideGenerativeUI, standardUI } from "@copilotkit/angular/generative-ui";

providers: [
  provideCopilotKit({ runtimeUrl: "/api/copilotkit" }),
  provideGenerativeUI({ ui: standardUI }),
],
<script setup lang="ts">
import { CopilotKitProvider } from "@copilotkit/vue/v2";
import { standardUI } from "@copilotkit/vue/v2/generative-ui";
</script>

<template>
  <CopilotKitProvider runtime-url="/api/copilotkit" :generativeUI="{ ui: standardUI }">
    <slot />
  </CopilotKitProvider>
</template>

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. In Angular, also add provideGenerativeUIMap() from @copilotkit/angular/generative-ui/map to the root providers. In Vue, also add app.use(GenerativeUIMap) from @copilotkit/vue/v2/generative-ui/map.
  • Chart works out of the box. It uses recharts, which comes with CopilotKit. In Angular, Chart draws with chart.js and Icon with lucide: install them and add provideGenerativeUIChart() and provideGenerativeUIIcons() from the /chart and /icons entries of @copilotkit/angular/generative-ui. Without them, a chart shows its data as a table and an icon shows nothing. In Vue, Chart draws with chart.js: install it and add app.use(GenerativeUIChart) from @copilotkit/vue/v2/generative-ui/chart. Without it, a chart shows its data as a table. Icons work with no setup.

Each standalone component has a dedicated page with the existing live examples, copyable surface operations, and API reference. Structural parts are documented on their parent component's page. Previews use local sample data and do not require a model connection.

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 },
  },
});
import { createGenerativeUI, standardUI } from "@copilotkit/angular/generative-ui";

export const appUI = createGenerativeUI({
  id: "acme/app@1",
  extends: [standardUI],
  components: {
    ProductCard: { component: ProductCard, props: productSchema },
  },
});
import { createGenerativeUI, standardUI } from "@copilotkit/vue/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 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: {},
});
import { Component, input } from "@angular/core";
import {
  CopilotGenerativeUIChildren,
  createGenerativeUI,
  standardUI,
  type GenerativeUIChildren,
} from "@copilotkit/angular/generative-ui";

@Component({
  selector: "app-card",
  imports: [CopilotGenerativeUIChildren],
  template: `
    <div class="rounded-2xl border p-6 shadow-sm">
      <ng-container *copilotGenerativeUIChildren="child()" />
      <ng-container *copilotGenerativeUIChildren="children()" />
    </div>
  `,
})
export class MyCard {
  readonly child = input<GenerativeUIChildren>();
  readonly children = input<GenerativeUIChildren>();
}

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

Declare an input() for each prop that your component reads. GenerativeUIComponentInputs<typeof standardUI, "Card"> has their types.

Card has two slots: child and children. Render both as named slots:

src/components/MyCard.vue
<template>
  <div class="rounded-2xl border p-6 shadow-sm">
    <slot name="child" />
    <slot name="children" />
  </div>
</template>
import { createGenerativeUI, standardUI } from "@copilotkit/vue/v2/generative-ui";
import MyCard from "./components/MyCard.vue";

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

MyCard is not in its own catalog, so it can read its prop types from GenerativeUIComponentProps<typeof standardUI, "Card">. Declare each prop that it reads in defineProps.

  • 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.