---
title: "InsightCards"
description: "A pager of insights: a conclusion, a card, and a follow-up per page."
category: AiContext
status: beta
since: 0.3.9
tags: [ai, insight, pager, data]
syncStatus: reviewed
verified: true
---

## Usage

### Full Composition
The component owns the title, paging, conclusion, and follow-up; the default slot supplies the card, such as `TxSparkChart`, `TxChartScrubber`, or `TxAllocationBar`.
:::TuffDemoWrapper{demo="InsightCardsInsightCardsDemo" code-lang="vue"}
---
code: |
  <script setup lang="ts">
  import { ref } from 'vue'

  const page = ref(0)
  const pages = [
    { key: 'compare', prose: 'The worst performer is Rocky Road — down 6%.', suggestion: 'Should I rebalance flavors?' },
    { key: 'allocation', prose: 'You are heavily invested in Vanilla — 72.5% of your case.', suggestion: 'What changes for seasonals?' },
  ]
  </script>

  <template>
    <TxInsightCards v-model:active-index="page" :pages="pages" @follow-up="ask($event)">
      <template #default="{ page: current }">
        <FlavourCard :key="current.key" />
      </template>
    </TxInsightCards>
  </template>
---
:::

### Figure Blocks
Through the default formatting, `value` uses a U+2212 minus (`−`), which aligns under `tabular-nums`.
:::TuffDemoWrapper{demo="InsightCardsInsightMetricDemo" code-lang="vue"}
---
code: |
  <template>
    <TxInsightMetric
      label="Mint Chip"
      color="var(--tx-bui-orange)"
      :value="-4.41"
      detail="−$2,377.66"
    />
    <TxInsightMetric
      label="Pistachio"
      color="var(--tx-bui-accent)"
      :value="1.15"
      detail="+$617.22"
    />
  </template>
---
:::

### Best Practices

- One point per page: a conclusion, one piece of evidence, and one actionable follow-up.
- Put entity mentions and inline figures in the `prose` slot; `page.prose` takes plain text only.
- Let the card body hold its own height, or the page jumps as you step through.
- Key the card in the slot with `page.key`, so paging rebuilds it and charts repaint.
- Word the follow-up the way a person would ask it, not "Learn more".

## API Reference

### TxInsightCards

#### Props

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `pages` | `InsightPage[]` | — | Page data, `{ key, prose?, suggestion? }`. |
| `activeIndex` | `number` | — | Current page, clamped into range; omit to let the component page itself. |
| `title` | `string` | `'Insights'` | Header title. |
| `showCount` | `boolean` | `true` | Shows the page count beside the title. |
| `loop` | `boolean` | `true` | Wraps at both ends; when off, the end buttons disable. |
| `previousLabel` / `nextLabel` | `string` | `'Previous insight'` / `'Next insight'` | Accessible names for the step buttons. |

#### Events

| Event | Payload | Description |
|------|------|-------------|
| `update:activeIndex` | `(index: number)` | Fires when the page moves. |
| `change` | `(page, index)` | Fires with `update:activeIndex`, carrying the page. |
| `followUp` | `(page)` | Fires when the follow-up pill is pressed. |

#### Slots

| Slot | Scope | Description |
|------|------|-------------|
| `default` | `{ page, index }` | The card body. |
| `prose` | `{ page, index }` | Rich conclusion copy, replacing `page.prose`. |
| `follow-up` | `{ page, index }` | Replaces the follow-up pill. |

#### Exposed Methods

| Method | Description |
|------|-------------|
| `previous()` / `next()` / `goTo(index)` | Imperative paging, down the same path as the buttons. |

### TxInsightMetric

#### Props

| Name | Type | Default | Description |
|------|------|---------|-------------|
| `label` | `string` | — | The caption. |
| `color` | `string` | — | Swatch before the label; omit to drop the dot. |
| `value` | `number` | — | Signed headline number, through the default formatting. |
| `delta` | `string` | — | Pre-formatted headline, used verbatim; wins over `value`. |
| `unit` | `string` | `'%'` | Unit appended by the default formatting. |
| `precision` | `number` | `2` | Decimals for the default formatting. |
| `detail` | `string` | — | Mono second line, used verbatim; write its minus as `−` yourself. |
| `tone` | `'positive' \| 'negative' \| 'neutral'` | — | Overrides the tone derived from the sign. |
| `formatter` | `(value: number) => string` | — | Takes over number formatting entirely. |

## Overview

- Without `activeIndex` the component pages itself; bind it and the host owns the page.
- Paging is a hard cut, with no transition and no autoplay; wrap the default slot's content in your own `<Transition>` for one.
- With `loop` off, the end button is natively `disabled`; an empty `pages` renders only the header, with both buttons disabled.
- A page without `suggestion` renders no follow-up pill.
- `TxInsightMetric` derives its tone from the sign by default: positive green, negative red, zero neutral.
- Headline figures and the page count use `tabular-nums`, so digits keep their width as you page.

## Technologies

- Adapted from [Beautiful UI](https://www.beautifului.dev) (© 2026 Shane Levine, MIT).
- Source: `packages/tuffex/packages/components/src/insight-cards/`.

<TuffDocSourceLink />
