AI insight
AIProAn AI generated insight callout for dashboards: a finding in one headline, the explanation, the number behind it, sources, actions and feedback.
npx prodular-ui add ai-insightPart of Prodular UI Pro. Preview and read the docs freely, install with a license. See pricing
On a dashboard
The one tinted surface in the view. Open the sources, rate it or dismiss it.
Spend on compute rose 38% after the September 9 deploy
The nightly ledger export now runs on every workspace instead of only active ones. It accounts for $11,900 of the increase. Usage outside the export is flat.
"use client"
import * as React from "react"import { ArrowRightIcon } from "lucide-react"
import { AiInsight, AiInsightActions, AiInsightBody, AiInsightContent, AiInsightDescription, AiInsightDismiss, AiInsightFeedback, AiInsightFooter, AiInsightHeader, AiInsightMetric, AiInsightSource, AiInsightSources, AiInsightTitle,} from "@/components/ui/ai-insight"import { Button } from "@/components/ui/button"
export default function AiInsightDashboard() { const [visible, setVisible] = React.useState(true)
return ( <div className="mx-auto flex w-full max-w-3xl flex-col gap-4"> {visible ? ( <AiInsight> <AiInsightHeader time="Detected 2 hours ago" model="Atlas 2"> <AiInsightDismiss onClick={() => setVisible(false)} /> </AiInsightHeader> <AiInsightBody> <AiInsightContent> <AiInsightTitle>Spend on compute rose 38% after the September 9 deploy</AiInsightTitle> <AiInsightDescription> The nightly ledger export now runs on every workspace instead of only active ones. It accounts for $11,900 of the increase. Usage outside the export is flat. </AiInsightDescription> </AiInsightContent> <AiInsightMetric label="Compute, last 14 days" value="$43,210" change="+38% vs prior 14 days" trend="up" sentiment="negative" /> </AiInsightBody> <AiInsightFooter> <AiInsightActions> <Button size="sm"> Investigate <ArrowRightIcon data-icon="inline-end" /> </Button> <Button size="sm" variant="ghost" onClick={() => setVisible(false)}> Dismiss </Button> </AiInsightActions> <AiInsightSources count={3}> <AiInsightSource href="#" title="Cloud billing export" description="Sep 1 to Oct 20, 1,284 line items" /> <AiInsightSource href="#" title="Deploy log, release 2026.09.09" description="ledger-export schedule changed" /> <AiInsightSource href="#" title="Workspace activity" description="412 active of 1,960 workspaces" /> </AiInsightSources> <AiInsightFeedback /> </AiInsightFooter> </AiInsight> ) : ( <div className="flex items-center justify-between rounded-xl border border-dashed px-4 py-3 text-[13px] text-muted-foreground"> Insight dismissed. It will not come back for this deploy. <Button size="xs" variant="ghost" onClick={() => setVisible(true)}> Show again </Button> </div> )}
<div className="grid grid-cols-2 gap-y-4 rounded-xl border bg-card py-4 shadow-xs sm:flex sm:divide-x"> {[ ["Total spend", "$186,420", "+9.2%"], ["Compute", "$43,210", "+38.0%"], ["Storage", "$12,880", "+1.4%"], ["Seats", "$61,200", "0.0%"], ].map(([label, value, change]) => ( <div key={label} className="flex min-w-0 flex-1 flex-col gap-1 px-4"> <span className="text-[13px] text-muted-foreground">{label}</span> <span className="text-lg font-medium tabular-nums">{value}</span> <span className="text-[13px] text-muted-foreground tabular-nums">{change} this month</span> </div> ))} </div> </div> )}Compact
A single row above a list, for findings that need one action.
9 billing tickets today trace back to the October 14 card retry
- #48213Charged twice for the Team planLena Fischer12 min
- #48209Second invoice this monthRui Tanaka40 min
- #48197Refund not received yetAmara Diallo2 h
"use client"
import * as React from "react"
import { AiInsight, AiInsightActions, AiInsightBody, AiInsightContent, AiInsightDismiss, AiInsightFooter, AiInsightHeader, AiInsightTitle,} from "@/components/ui/ai-insight"import { Button } from "@/components/ui/button"
const tickets = [ ["#48213", "Charged twice for the Team plan", "Lena Fischer", "12 min"], ["#48209", "Second invoice this month", "Rui Tanaka", "40 min"], ["#48197", "Refund not received yet", "Amara Diallo", "2 h"],]
export default function AiInsightCompact() { const [visible, setVisible] = React.useState(true) return ( <div className="mx-auto flex w-full max-w-2xl flex-col gap-3"> {visible && ( <AiInsight size="compact"> <AiInsightHeader label="Insight" /> <AiInsightBody> <AiInsightContent> <AiInsightTitle>9 billing tickets today trace back to the October 14 card retry</AiInsightTitle> </AiInsightContent> </AiInsightBody> <AiInsightFooter> <AiInsightActions> <Button size="xs" variant="outline"> Group them </Button> <AiInsightDismiss onClick={() => setVisible(false)} /> </AiInsightActions> </AiInsightFooter> </AiInsight> )} <div className="rounded-xl border bg-card shadow-xs"> <ul className="divide-y text-sm"> {tickets.map(([id, subject, name, age]) => ( <li key={id} className="flex items-center gap-4 px-4 py-2.5"> <span className="font-mono text-xs text-muted-foreground">{id}</span> <span className="min-w-0 flex-1 truncate">{subject}</span> <span className="text-muted-foreground">{name}</span> <span className="w-12 text-right text-[13px] text-muted-foreground tabular-nums">{age}</span> </li> ))} </ul> </div> </div> )}Anatomy
<AiInsight> <AiInsightHeader time="Detected 2 hours ago"> <AiInsightDismiss /> </AiInsightHeader> <AiInsightBody> <AiInsightContent> <AiInsightTitle>Spend on compute rose 38% after the September 9 deploy</AiInsightTitle> <AiInsightDescription>Why, in two sentences.</AiInsightDescription> </AiInsightContent> <AiInsightMetric label="Compute, last 14 days" value="$43,210" change="+38%" trend="up" sentiment="negative" /> </AiInsightBody> <AiInsightFooter> <AiInsightActions> <Button size="sm">Investigate</Button> </AiInsightActions> <AiInsightSources count={3} /> <AiInsightFeedback /> </AiInsightFooter></AiInsight>Guidance
Use it when
- Use it for a finding the model made from the person's data that they would not see on their own: a change, an anomaly, a cause.
- Write the title as the finding with the number and the cause: Spend on compute rose 38% after the September 9 deploy.
- Back it with AiInsightMetric and list the data it used in AiInsightSources.
- Give it one primary action that leads to the evidence, such as Investigate, and a way to dismiss it.
Avoid
- More than one AiInsight in a view. It is the one tinted highlight. Rank findings and show the top one, list the rest elsewhere.
- Generic advice that does not come from the data, such as Consider reducing costs.
- Putting it inside a card. It is a container itself.
Rules for AI agents
Published in llms-full.txt, the registry and the MCP server, so coding agents follow them when they build with this component.
- Render at most one AiInsight per view and never nest it inside a Card or another bordered container.
- The title must state a specific finding with a number and, when known, the cause or date. Keep it under 90 characters.
- Always include AiInsightSources with the real count of sources the model used, and pass children listing them when they can be opened.
- Set AiInsightMetric sentiment from the business meaning: rising cost or churn is negative, rising revenue is positive.
- Include AiInsightDismiss and remember the dismissal so the same insight does not come back. Send AiInsightFeedback to your evaluation pipeline with onFeedback.
API
AiInsight
| Prop | Type | Default | Description |
|---|---|---|---|
| size | "default" | "compact" | "default" | compact is one row: mark, title and actions. |
AiInsightHeader
| Prop | Type | Default | Description |
|---|---|---|---|
| label / time / model | string / ReactNode / string | "Insight" | Badge label, when it was found and the model in the mark's tooltip. Children sit on the right. |
AiInsightMetric
| Prop | Type | Default | Description |
|---|---|---|---|
| label / value / change | ReactNode | The supporting number. | |
| trend / sentiment | "up" | "down" / "positive" | "negative" | "neutral" | Direction icon and color of the change. |
AiInsightSources
| Prop | Type | Default | Description |
|---|---|---|---|
| count | number | Number of sources. Children open in a popover. |
AiInsightFeedback
| Prop | Type | Default | Description |
|---|---|---|---|
| onFeedback | (value: "up" | "down") => void | Called once per insight. |
Installation
The Prodular UI CLI adds the source to components/ui with everything it depends on. In a project that already uses shadcn/ui, the shadcn CLI installs it from the Prodular registry too. See Installation for the first setup.
npx prodular-ui add ai-insight# or, with the registry in components.jsonnpx shadcn@latest add @prodular/ai-insight