Production-ready pattern components for ChatGPT Apps
100% compatible with @openai/apps-sdk-ui. Use their primitives + our patterns = ship faster.
Live Storybook · Quick Start · Components
| Without this library | With @ainativekit/ui |
|---|---|
| Build card layouts from scratch | <SummaryCard {...data} /> |
| Wire up carousels manually | <Carousel>{items}</Carousel> |
| Create map components yourself | <CompactMap locations={...} /> |
| Write ChatGPT integration hooks | useTheme(), useDisplayMode(), useWidgetState() |
Fully compatible with apps-sdk-ui - use their 700+ icons, buttons, badges, and design tokens alongside our pattern components.
┌─────────────────────────────────────────┐
│ Your ChatGPT App │
├─────────────────────────────────────────┤
│ @ainativekit/ui (Pattern Components) │
│ Card, Album, Carousel, List, Map │
├─────────────────────────────────────────┤
│ @openai/apps-sdk-ui (Primitives) │
│ Button, Badge, Icon, Alert, Avatar │
└─────────────────────────────────────────┘
| Category | Components |
|---|---|
| Cards | Card, SummaryCard, ImageCard, ListCard |
| Media | Album, Carousel, PhotoCarousel |
| Lists | List, ListItem, AvatarList |
| Maps | CompactMap, FullscreenMap, MapPlaceCard |
| Feedback | Modal, Sidebar, Skeleton, Overlay |
| ChatGPT Hooks | useTheme, useDisplayMode, useMaxHeight, useWidgetState |
npm install @ainativekit/ui @openai/apps-sdk-uiimport '@openai/apps-sdk-ui/css';
import '@ainativekit/ui/styles';import { SummaryCard } from '@ainativekit/ui';
import { StarFilled, Clock } from '@openai/apps-sdk-ui/components/Icon';
function RestaurantCard({ data }) {
return (
<SummaryCard
images={data.images}
title={data.name}
subtitle={data.address}
badge={data.rating}
description={data.description}
metadata={[
{ icon: <StarFilled />, label: data.rating },
{ icon: <Clock />, label: 'Open now' }
]}
buttonText="Reserve"
onButtonClick={() => {}}
/>
);
}import { Card, SummaryCard, ImageCard, ListCard } from '@ainativekit/ui';
// Compound card for custom layouts
<Card elevationLevel={1} interactive>
<Card.Image src="..." />
<Card.Body>
<Card.Title>Title</Card.Title>
<Card.Description>Description</Card.Description>
</Card.Body>
<Card.Footer>
<Card.ActionButton>Action</Card.ActionButton>
</Card.Footer>
</Card>
// Pre-composed cards
<SummaryCard images={...} title="..." description="..." />
<ImageCard images={...} title="..." />
<ListCard items={...} />import { Carousel } from '@ainativekit/ui';
<Carousel>
{items.map(item => (
<SummaryCard key={item.id} {...item} />
))}
</Carousel>import { List, ListItem } from '@ainativekit/ui';
import { StarFilled } from '@openai/apps-sdk-ui/components/Icon';
<List
header={{ title: 'Top Places', subtitle: 'Based on ratings' }}
items={places}
renderItem={(place, index) => (
<ListItem
rank={index + 1}
title={place.name}
metadata={place.city}
media={place.thumbnail}
features={[{ icon: <StarFilled />, label: place.rating }]}
/>
)}
/>import { Album } from '@ainativekit/ui';
<Album
albums={[
{
id: '1',
title: 'Photos',
cover: '...',
photos: [{ id: '1', url: '...', title: '...' }]
}
]}
onAlbumSelect={setSelectedAlbum}
selectedAlbum={selectedAlbum}
/>import { CompactMap } from '@ainativekit/ui';
import { StarFilled } from '@openai/apps-sdk-ui/components/Icon';
<CompactMap
locations={[
{
id: '1',
name: 'Restaurant',
coords: [37.7749, -122.4194],
features: [{ icon: <StarFilled />, label: '4.8' }]
}
]}
onLocationSelect={setSelected}
/>Hooks for integrating with the ChatGPT Apps SDK runtime - unique to @ainativekit/ui:
import {
useTheme,
useDisplayMode,
useMaxHeight,
useWidgetState,
useOpenAiGlobal,
} from '@ainativekit/ui';
function MyWidget() {
const { theme } = useTheme(); // 'light' | 'dark'
const displayMode = useDisplayMode(); // 'inline' | 'pip' | 'fullscreen'
const maxHeight = useMaxHeight(); // number | null
const [state, setState] = useWidgetState(() => ({ count: 0 }));
return (
<div style={{ maxHeight: maxHeight ?? 600 }}>
{/* widget content */}
</div>
);
}| Hook | Description |
|---|---|
useTheme() |
Get current theme from ChatGPT |
useDisplayMode() |
Get display mode (inline/pip/fullscreen) |
useMaxHeight() |
Get max height constraint |
useWidgetState() |
Persistent state across re-renders |
useWidgetProps() |
Access tool input/output |
useOpenAiGlobal(key) |
Access any window.openai property |
Icons, buttons, and other primitives come directly from @openai/apps-sdk-ui:
// 700+ Icons
import { StarFilled, Clock, MapPin } from '@openai/apps-sdk-ui/components/Icon';
// Buttons
import { Button } from '@openai/apps-sdk-ui/components/Button';
// Badges
import { Badge } from '@openai/apps-sdk-ui/components/Badge';
// Alerts
import { Alert } from '@openai/apps-sdk-ui/components/Alert';
// Empty state
import { EmptyMessage } from '@openai/apps-sdk-ui/components/EmptyMessage';
// Breakpoints hook
import { useBreakpoint } from '@openai/apps-sdk-ui/hooks/useBreakpoints';Note: AINativeKit does not re-export SDK primitives. Import Button, Badge, Alert, etc. directly from
@openai/apps-sdk-uito ensure CSS variables are loaded correctly.
Full TypeScript support with window.openai types:
import type { Theme, DisplayMode, LocationData } from '@ainativekit/ui';
// window.openai is fully typed when you import @ainativekit/ui
const theme = window.openai?.theme; // 'light' | 'dark' | undefinedpnpm install # install deps
pnpm storybook # run interactive docs
pnpm test # run tests
pnpm build # build the library- Live Storybook - Interactive examples
- GitHub
- apps-sdk-ui - Base primitives
MIT