Skip to content
LogoLogo

AI Card

Loading...

Loading...

Overview

Resources

Loading...

Loading...

Loading...

Loading...

Install

yarn add @camp/ai-card

Basic Card Usage

The AI Card is exported with several helper components that can be used to style the card content.

  • Card - The main card wrapper.
  • StyledCardHeader - The header content of the card.
  • StyledCardBody - The body content of the card; set hasHeader to true to remove the top padding on the body content.
  • HeaderText - The text for the header; includes ellipsis truncation styling for long titles.
  • ChartWrapper - The wrapper for a chart component; set a string value for height to set the height of the chart container (for use with ResponsiveContainer).

Example

This card includes a header and body content.

import { Card, HeaderText, StyledCardHeader, StyledCardBody } from '@camp/ai-card';
 
<Card>
  <StyledCardHeader>
    <HeaderText>
      Card Header with a long title that should not wrap but should be truncated
    </HeaderText>
  </StyledCardHeader>
  <StyledCardBody>
    {' '}
    // You can optionally set `hasHeader` to `true` to remove the top padding on this body content.
    This is a basic card with a header and body content. The card component is flexible and can be
    used for various content types.
  </StyledCardBody>
</Card>;

Chart Wrapper

AI Cards can include a chart component using ChartWrapper. Set a string value for height to set the height of the chart container (for use with ResponsiveContainer).

import { Card, StyledCardHeader, StyledCardBody, HeaderText, ChartWrapper } from '@camp/ai-card';
 
<Card>
  <StyledCardHeader>
    <HeaderText>Chart Container</HeaderText>
  </StyledCardHeader>
  <StyledCardBody>
    <ChartWrapper height="200px">
      {' '}
      // Set a string value for `height` to set the height of the chart container (for use with
      `ResponsiveContainer`)
      <div>Chart content would go here</div>
    </ChartWrapper>
  </StyledCardBody>
</Card>;

Block Card Usage

Block Cards are an interactive variation of the AI Card component. They have a responsive layout based on the width of the card container.

Example

import { BlockCard } from '@camp/ai-card';
 
// Example stock images
const sampleImages = [
  'https://picsum.photos/id/15/200/300',
  'https://picsum.photos/id/19/200/300',
  'https://picsum.photos/id/17/200/300',
];
 
function Example() {
  return (
    <div style={{ width: '600px' }}>
      <BlockCard
        type="automation" // Current available types are "automation" and "campaign_id"
        title="7-Day Welcome Drip Campaign"
        description="A 7-day email sequence to nurture new leads and increase engagement with your hardware store."
        isLoadingData={false}
        isLoadingImages={false}
        isOpen={false}
        images={sampleImages}
        maxImages={3}
        onClick={() => undefined}
      />
    </div>
  );
}

Props

PropTypeDefaultDescription
description *stringThe description text
onClick *() => voidThe function to call when the block card is clicked
title *stringThe title text
images *string[]The images to display in the block card; to render no images, pass an empty array
isOpen *booleanWhether the block card should display an open/active state
maxImages *numberThe maximum number of images to display
type *stringThe type determines the text rendered in the top left corner (this will be deprecated in the near future)
isLoadingData *booleanWhether the block card is loading data
isLoadingImages *booleanWhether the block card is loading images
isDisabledbooleanWhether the block card is disabled
renderChipReactNodeThe chip to display in the top left corner
renderPreviewReactNodeOptionally render a custom component in the image preview container; this will override any images passed in
currencystringCurrency code (required when metricFormat is 'currency')
illustrationReactNodeThe illustration to display in the top left corner
localestringen-USLocale for formatting (e.g., 'en-US'). Defaults to 'en-US'
metricnumberThe metric number to display in the top right corner. This prop and `metricFormat` are required in order to display metric data.
metricFormat"currency" | "integer" | "percent" | "float"How to format the metric. This prop and `metric` are required in order to display metric data.
metricUnitLabelstringThe metric unit label to display in the top right corner

Generated from @camp/ai-card@9.17.0 source, ordered by production usage. * required.

Loading states

The Block Card supports loading states for both data and images.

isLoadingData

When prop isLoadingData is set to true, the card will display this loading state for the data content.

isLoadingImages

When prop isLoadingImages is set to true, the card will display this loading state for the images.

isLoadingData & isLoadingImages

When props isLoadingData and isLoadingImages are both set to true, the card will display this loading state for both the data and images.

Open state

When prop isOpen is set to true, the card will display this open state. This matches the active pseudo state styles and is meant to be used when the card is active, such as when a user clicks on the card from the ActiveIntelligence sidebar and the relevant content is actively being displayed.

Truncation behavior

When the title or the description text is too long, it will be truncated with an ellipsis.

Disabled state

When prop isDisabled is set to true, the card will display this disabled state.

Insight Card Usage

The AI Insight Card is designed to display AI-generated insights to users in a consistent and actionable format. These cards present important information like optimizations, new opportunities, growth milestones, or alerts that require user attention.

Basic usage

An Insight Card requires a title, timestamp, and a callback function for the CTA button. The component supports multiple insight types with predefined styling and text.

import { AiInsightCard } from '@camp/ai-card';
 
function Example() {
  const handleCtaClick = () => {
    console.log('CTA clicked');
  };
 
  return (
    <AiInsightCard
      type="optimization"
      title="Improve email engagement"
      description="Your recent campaigns show lower-than-average open rates. Consider adjusting send times."
      timestamp="2 hours ago"
      onCtaClick={handleCtaClick}
    />
  );
}

Insight types

The Insight Card supports four predefined types, each with its own default chip styling and CTA text:

  • optimization: Optimizations are insights that include a drafted update to an object, such as an automation, email, SMS, etc that already exists. It includes data to back the insight, recommended next steps, and a draft of the update for the user to review. (default chip text: "Optimization", default CTA: "Preview updates")
  • new_opportunity: New opportunities are data-driven insights, where the next best action is a drafted newly created object, such as an automation, email, SMS, etc. (default chip text: "New opportunity", default CTA: "Preview draft")
  • growth_milestone: Account growth milestones are celebratory moments for the account, including number of contacts, number of email sends or automations activated, open/click rate, etc. records, and more. (default chip text: "Growth milestone", default CTA: "View report")
  • alert: Urgent, high-priority notifications from agents monitoring for problems. Alert cards should ALWAYS show first in the row, regardless of timestamp. The chipText in Alert cards should be set to be as clear as possible about the issue at hand (e.g., "Delivery Issue Detected", "Integration Connection Issue"). This type requires custom chipText. (default CTA: "Review and fix")
import { AiInsightCard } from '@camp/ai-card';
 
// Optimization type
<AiInsightCard
  type="optimization"
  title="Improve email engagement"
  timestamp="2 hours ago"
  onCtaClick={handleToggleAiSidebar}
  // Default CTA text is "Preview updates"
/>
 
// New opportunity type
<AiInsightCard
  type="new_opportunity"
  title="Expand to new audience segment"
  timestamp="1 day ago"
  onCtaClick={handleToggleAiSidebar}
  // Default CTA text is "Preview draft"
/>
 
// Growth milestone type
<AiInsightCard
  type="growth_milestone"
  title="Reached 10,000 subscribers"
  timestamp="3 days ago"
  onCtaClick={handleToggleAiSidebar}
  // Default CTA text is "View report"
/>
 
// Alert type (requires custom chipText)
<AiInsightCard
  type="alert"
  chipText="Delivery issue detected"
  title="Campaign delivery delays"
  timestamp="30 minutes ago"
  onCtaClick={handleToggleAiSidebar}
  // Default CTA text is "Review and fix"
/>

Expanded content

Insight Cards can include additional expandable content that appears when the user clicks "See more". Clicking "See less" collapses it. Expanded cards expand over top of page content. Their height is not considered within the insight card row.

Expanded state is controlled within the component, so no external state management is needed. When content is provided to the expandedContent prop, "See more" will be displayed indicating that expanded content is available.

Active state

When an insight is currently being viewed or acted upon (opened in Active Intelligence via the card CTA), set the active prop to true. This applies a border-color change to indicate the card is active and changes the CTA text to "Close Active Intelligence". Clicking the CTA then acts as an additional way to close the AI Sidebar.

import { AiInsightCard } from '@camp/ai-card';
 
<AiInsightCard
  type="optimization"
  title="Improve email engagement"
  timestamp="2 hours ago"
  active={true}
  onCtaClick={handleToggleAiSidebar}
/>;

Insight status

Insight cards have two primary status states that affect their visual appearance and behavior:

New

When a user has not yet opened a card in Active Intelligence via the CTA, it is considered to have "New" status. Set the status prop to "new" to display this status with success color.

All other statuses

Status is not required, but if another status is needed, set the status prop to the desired status. Any status value other than "new" (case-insensitive) displays with a supportive color.

import { AiInsightCard } from '@camp/ai-card';
 
// New status (success color)
<AiInsightCard
  type="optimization"
  title="Improve email engagement"
  timestamp="2 hours ago"
  status="new"
  onCtaClick={handleToggleAiSidebar}
/>
 
// Other status (supportive color)
<AiInsightCard
  type="optimization"
  title="Previous recommendation"
  timestamp="1 week ago"
  status="viewed"
  onCtaClick={handleToggleAiSidebar}
/>

Custom chip and CTA text

You can override the default chip text (chipText) and CTA button text (ctaText) for any type, or provide a completely custom chip component (typeChip).

import { AiInsightCard } from '@camp/ai-card';
import { Chip } from '@camp/chip';
 
// Override default text
<AiInsightCard
  type="optimization"
  chipText="Custom optimization chip text"
  ctaText="Custom optimization CTA text"
  title="Urgent optimization needed"
  timestamp="5 minutes ago"
  onCtaClick={handleToggleAiSidebar}
/>
 
// Custom chip component
<AiInsightCard
  typeChip={<Chip color="violet">Custom Chip</Chip>}
  ctaText="View details"
  title="Custom insight type"
  timestamp="1 hour ago"
  onCtaClick={handleToggleAiSidebar}
/>

Layout with AiInsightCardRow

Insight Cards should always be placed within an AiInsightCardRow component for proper layout. The row supports up to three cards and handles responsive sizing automatically.

import { AiInsightCard, AiInsightCardRow } from '@camp/ai-card';
 
function Example() {
  return (
    <AiInsightCardRow>
      <AiInsightCard
        type="optimization"
        title="Improve email engagement"
        timestamp="2 hours ago"
        onCtaClick={() => handleToggleAiSidebar(someData)}
      />
      <AiInsightCard
        type="new_opportunity"
        title="Expand to new audience"
        timestamp="1 day ago"
        onCtaClick={() => handleToggleAiSidebar(someData)}
      />
      <AiInsightCard
        type="growth_milestone"
        title="Reached 10,000 subscribers"
        timestamp="3 days ago"
        onCtaClick={() => handleToggleAiSidebar(someData)}
      />
    </AiInsightCardRow>
  );
}

Layout guidelines

  • Maximum 3 cards per row: Never place more than three Insight Cards in a single row. There should never be more than three cards per page.
  • Alert priority: Alert cards should ALWAYS show first in the row, regardless of timestamp.

Layout concerns handled automatically:

  • Responsive width: Single card 50% of row width; 2 cards: Stretch to fill equal width; 3 cards: Stretch to fill equal width.
  • Height matching: All cards in a row automatically match the height of the tallest card. Insight cards within a row grow in height to match the tallest card in a row.
  • Action alignment: Actions (CTA buttons) are aligned to the bottom of the card.

Z-index for expanded content

For greater control over stacking context, use the zIndex prop on AiInsightCardRow. This is helpful within pages that have multiple stacking contexts and the expanded content needs to be lifted up to appear above other page elements.

import { AiInsightCard, AiInsightCardRow } from '@camp/ai-card';
 
// Use zIndex when expanded content needs to appear above other elements
<AiInsightCardRow zIndex={10}>
  <AiInsightCard
    type="optimization"
    title="Insight with expanded content"
    timestamp="1 hour ago"
    expandedContent={<div>{/* Expanded content */}</div>}
    onCtaClick={handleToggleAiSidebar}
  />
</AiInsightCardRow>;

A featured insight can surface KPIs, a longer description, and a media region (for example a chart preview). Set mediaCtaClickable when the chart or preview area should use the same onCtaClick handler as the main CTA—for instance, opening a preview—instead of only the footer button.

import { AiInsightCard, ChartWrapper } from '@camp/ai-card';
 
function Example() {
  const kpis = [
    { label: 'Open rate', value: '42%' },
    { label: 'Click rate', value: '3.2%' },
  ];
 
  return (
    <div style={{ maxWidth: '900px' }}>
      <AiInsightCard
        type="optimization"
        timestamp="8m ago"
        title="Featured: KPIs + description + clickable media region"
        description="Your recent performance data suggests focusing on send time and subject line testing."
        featured
        featuredLabel="High impact"
        kpis={kpis}
        mediaCtaClickable
        onCtaClick={() => {
          console.log('Preview updates');
        }}
        media={
          <ChartWrapper height="200px">
            <div>Chart / preview</div>
          </ChartWrapper>
        }
      />
    </div>
  );
}

Props

AiInsightCard

PropTypeRequiredDefaultDescription
type'optimization' | 'new_opportunity' | 'growth_milestone' | 'alert'Conditional-Type determines default chip text, chip color, and CTA button text. Required unless using typeChip
titlestring-The title of the insight
timestampstring-The timestamp of the insight (e.g., "2 hours ago")
onCtaClick() => void-Callback function called when the CTA button is clicked
descriptionstring-Optional description text displayed below the title
expandedContentReact.ReactNode-The content to display when the insight is expanded
activebooleanfalseSet to true to apply active styling and change CTA text to "Close Active Intelligence"
statusstring-Status indicator. Value "new" (case-insensitive) shows with 'success' color, any other value shows with 'supportive' color
chipTextstringConditional-Override for default chip text. Required when type is "alert"
ctaTextstringConditional-Override for default CTA button text. Required when using typeChip. Overridden by active prop
typeChipReact.ReactNode-Custom React component to display instead of the default chip (mutually exclusive with type)
themedbooleantrueWhether the component should adapt to light/dark theme modes

AiInsightCardRow

PropTypeRequiredDefaultDescription
childrenReact.ReactNode-The insight card children to display in the row. Maximum of 3 cards
zIndexnumber-Optional z-index value to control stacking context. Use when expanded cards need to appear above other page content

Best practices

  • Use Block Cards for interactive content that users can click to expand or navigate
  • Set appropriate loading states to provide feedback during data fetching

Content guidelines

✅ DO

  • Use clear, descriptive titles that communicate the content purpose * Provide helpful descriptions that explain what the content does * Use appropriate block types that match the content category * Include relevant images that help users identify the content

🚫 DON’T

  • Use vague or generic titles that don't describe the content * Leave descriptions empty or use placeholder text * Mix different content types in the same block card * Use too many images that clutter the interface

Production Examples

More states from @camp/ai-card's visual test stories, ranked by production usage. Variations already documented above are not repeated here.

Block Card With Metrics And Chip

import { BlockCard } from '@camp/ai-card';
 
const exampleIllustration = (
  <SpotIllustration size="medium" use={illustrations.cartEcommerceShopSpot} />
);
 
const defaultArgs = {
  isLoadingData: false,
  isLoadingImages: false,
  isOpen: false,
  images: sampleImages,
  maxImages: 3,
  onClick: () => undefined,
};
 
<BlockCard
  {...defaultArgs}
  type="automation"
  onClick={() => {}}
  title="Campaign with Metrics and Chip"
  description="This card displays metrics with a custom chip in the top left."
  renderChip={<AiChip type="default">Business goal</AiChip>}
  metric={200000}
  metricFormat={'currency' as const}
  currency="USD"
  metricUnitLabel="revenue"
  illustration={exampleIllustration}
/>

Block Card With Metrics

import { BlockCard } from '@camp/ai-card';
 
const defaultArgs = {
  isLoadingData: false,
  isLoadingImages: false,
  isOpen: false,
  images: sampleImages,
  maxImages: 3,
  onClick: () => undefined,
};
 
<BlockCard
  {...defaultArgs}
  type="automation"
  title="7-Day Welcome Drip Campaign"
  description="A 7-day email sequence to nurture new leads and increase engagement with your hardware store."
  metric={1234}
  metricFormat={'integer' as const}
  metricUnitLabel="opens"
  onClick={() => {}}
/>

Block Card With Metrics And Illustration

import { BlockCard } from '@camp/ai-card';
 
const exampleIllustration = (
  <SpotIllustration size="medium" use={illustrations.cartEcommerceShopSpot} />
);
 
const defaultArgs = {
  isLoadingData: false,
  isLoadingImages: false,
  isOpen: false,
  images: sampleImages,
  maxImages: 3,
  onClick: () => undefined,
};
 
<BlockCard
  {...defaultArgs}
  type="automation"
  title="7-Day Welcome Drip Campaign"
  description="A 7-day email sequence to nurture new leads and increase engagement with your hardware store."
  metric={1234}
  metricFormat={'integer' as const}
  metricUnitLabel="opens"
  onClick={() => {}}
  illustration={exampleIllustration}
/>

Block Card Campaign

import { BlockCard } from '@camp/ai-card';
 
const defaultArgs = {
  isLoadingData: false,
  isLoadingImages: false,
  isOpen: false,
  images: sampleImages,
  maxImages: 3,
  onClick: () => undefined,
};
 
<BlockCard
  {...defaultArgs}
  type="campaign_id"
  title="Summer Promotion Campaign"
  description="Launch a targeted email campaign for summer promotions, including special offers and seasonal content for our customer base."
  onClick={() => {}}
/>

Block Card No Images

import { BlockCard } from '@camp/ai-card';
 
const defaultArgs = {
  isLoadingData: false,
  isLoadingImages: false,
  isOpen: false,
  images: sampleImages,
  maxImages: 3,
  onClick: () => undefined,
};
 
<BlockCard
  {...defaultArgs}
  type="automation"
  title="Card Without Images"
  description="This card has no images to display in the preview stack."
  images={[]}
  onClick={() => {}}
/>

Block Card No Images With Chip

import { BlockCard } from '@camp/ai-card';
 
const defaultArgs = {
  isLoadingData: false,
  isLoadingImages: false,
  isOpen: false,
  images: sampleImages,
  maxImages: 3,
  onClick: () => undefined,
};
 
<BlockCard
  {...defaultArgs}
  type="automation"
  title="Card With Chip"
  description="No images provided, so the large image area is removed."
  images={[]}
  renderChip={<AiChip type="default">Automation</AiChip>}
  onClick={() => {}}
/>

9 more variations in Storybook

Accessibility

Keyboard support

  • Tab: Navigate through interactive elements within the AI Card
  • Enter/Space: Activate buttons and interactive elements
Copyright © 2026 ActiveCampaign