BookbagBookbag

Components

The full widget component library — layout, text, form inputs, data display, media, and interactive components — with the JSX-like syntax for composing them.

View as Markdown

Widgets are composed from a fixed library of components. You combine them in JSX-like markup, set their properties as attributes, and pass data from the widget's schema. This page is the reference for every component, grouped by category.

tip

Properties are passed as attributes. Strings use quotes (color="primary"); numbers, objects, and data references use braces (gap={4}, value={title}).

Layout

Card is the outer container of every widget; Col and Row lay children out vertically or horizontally.

ComponentDescriptionCommon props
CardThe widget's outer container. Use asForm to make it a submittable form.size, background, theme, asForm
ColStacks children in a column.gap, padding, width, align
RowLays children out in a row.gap, align, padding
BoxA generic flex container.direction, wrap, padding
DividerA horizontal rule between sections.size, color, spacing
SpacerFlexible empty space that pushes siblings apart.minSize
<Card size="md">
  <Row gap={2} align="center">
    <Title value="Order #1024" size="md" weight="semibold" />
    <Spacer />
    <Badge label="Shipped" color="success" pill />
  </Row>
</Card>

Text

ComponentDescriptionCommon props
TitleA heading.value, size, weight
TextBody or secondary text (supports multiple lines).value, size, color
LabelA field label tied to an input.value, fieldName

Form inputs

Capture structured data inside the chat. Wrap them in a Card with asForm and submit with a Button submit.

ComponentDescriptionCommon props
InputA single-line text field.name, inputType, placeholder, required
TextareaA multi-line text field.name, rows, placeholder, required
SelectA dropdown of options.name, options, placeholder, block
CheckboxA single boolean checkbox.name, label
<Col gap={2}>
  <Label value="Company size" fieldName="companySize" />
  <Select name="companySize" placeholder="Select size"
    options={companySizes} block required />
</Col>

Data display

ComponentDescriptionCommon props
TableA data table container.
TableRowA table row; mark headers with header.header
TableCellA table cell.align, colSpan, rowSpan, width
ChartA bar / line / area chart rendered from data.data, series, xAxis, yAxis, showLegend
BadgeA small status pill or tag.label, color, variant, pill
ListViewA scrollable list or carousel of items.orientation, gap, limit
ListViewItemA single item within a ListView.gap

Media

ComponentDescriptionCommon props
ImageAn image, with fit and corner radius. Supports light/dark sources.src, height, fit, radius
IconAn icon from the built-in set (kebab-case names).name, size, color

Interactive

A Button runs a function via onClickAction; pass extra data along with additionalInputs.

ComponentDescriptionCommon props
ButtonA clickable button that runs a function or submits a form.label, variant, color, block, submit, onClickAction
<Button label="Add to cart" iconStart="shopping-cart"
  variant="solid" color="primary" block
  onClickAction={{ functionName: "addToCart",
    additionalInputs: { productId: product.id } }} />

Theming

Components use theme tokens (text colors like primary, secondary, tertiary; status colors like success, warning) and automatically adapt to a light or dark chat surface. You generally don't set raw colors — use the named tokens so widgets stay on-brand across themes.

Composing a full widget

Put it together — a product card built from layout, media, text, data display, and interactive components, repeated over a data array:

<Card size="md">
  <Col gap={3}>
    <Row gap={2} align="center">
      <Icon name="shopping-bag" size="sm" color="secondary" />
      <Text value={heading} size="sm" color="secondary" />
    </Row>
    <ListView orientation="horizontal" gap={2}>
      {products.map((product) => (
        <ListViewItem key={product.id}>
          <Col gap={2} width={240}>
            <Image src={product.image} height={190} fit="cover" radius="md" />
            <Title value={product.name} size="xs" weight="semibold" />
            <Text value={product.category} size="sm" color="secondary" />
            <Text value={product.price} size="md" weight="medium" />
            <Button label="Add to cart" variant="solid" color="primary" block
              onClickAction={{ functionName: "addToCart",
                additionalInputs: { productId: product.id } }} />
          </Col>
        </ListViewItem>
      ))}
    </ListView>
  </Col>
</Card>

What's next