Theming
CSS variable system matching ChatGPT's design palette for artifact rendering
ChatGPT Theme System
CSS variable system that matches ChatGPT's design system palette for artifact rendering.
Table of Contents
- Overview - Theme system architecture
- CSS Variable Palette - Available variables and values
- Implementation Pattern - How to apply themes
- Integration Points - Where themes are loaded
- Storybook Alignment - How previews match production themes
Overview
Artifacts in ChatGPT must match the platform's visual design system. The theme system provides CSS variables scoped to artifact containers using the data-artifact-container-chatgpt attribute.
Architecture:
- Theme file:
app/artifact/artifact-theme.css- Defines ChatGPT palette via CSS variables - Scope selector:
[data-artifact-container-chatgpt]- Scopes variables to artifact containers - Theme detection:
useTheme()hook appliesdarkclass to<body>element - CSS cascading:
.dark [data-artifact-container-chatgpt]overrides for dark mode
Key constraint: Variables are scoped to containers with data-artifact-container-chatgpt attribute. Components outside this scope use default browser/system colors.
CSS Variable Palette
All variables are defined under [data-artifact-container-chatgpt] selector.
Layout & Surface:
--background- Primary background color--foreground- Primary text color--card- Card background--card-foreground- Card text--popover- Popover/dropdown background--popover-foreground- Popover text--muted- Muted background (subtle areas)--muted-foreground- Muted text--secondary- Secondary surface background--secondary-foreground- Secondary text--accent- Accent background--accent-foreground- Accent text
Interactive Elements:
--border- Border color--input- Input field background--ring- Focus ring color--primary- Primary button/action color--primary-foreground- Text on primary--destructive- Destructive action color--destructive-foreground- Text on destructive
Chart Colors:
--chart-1through--chart-5- Sequential chart colors
Light mode values: White backgrounds (#ffffff), dark text (#0d0d0d), blue primary (#0285ff)
Dark mode values: Dark backgrounds (#212121, #303030, #414141), light text (#ffffff, #cdcdcd), same blue primary (#0285ff)
See app/artifact/artifact-theme.css for complete value definitions.
Implementation Pattern
Required steps:
- Wrap content in container with
data-artifact-container-chatgptattribute - Call
useTheme()hook to syncdarkclass with ChatGPT theme - Use CSS variables in component styles (automatically scoped)
Example from ArtifactViewer:
import { useTheme } from '../hooks';
export function ArtifactViewer() {
useTheme(); // Syncs dark class with ChatGPT theme
return (
<div data-artifact-container-chatgpt>
{/* Content uses CSS variables automatically */}
<Card className="bg-background text-foreground">
{/* ... */}
</Card>
</div>
);
}Why this pattern:
- Scoped variables prevent theme leakage to non-artifact content
data-artifact-container-chatgptclearly marks artifact boundariesuseTheme()ensures theme stays in sync with ChatGPT's preference- CSS variables enable automatic dark/light mode switching
Important: useTheme() applies dark class to <body>, not <html>, to avoid Next.js attribute stripping.
Integration Points
Theme file location: app/artifact/artifact-theme.css
Import chain:
app/globals.cssimports@chatgpt-artifacts/chatgpt-app/artifact-theme.css- Package exports defined in
package.jsonunder"./artifact-theme.css" - Styles available globally via CSS import, variables scoped by attribute selector
Hook integration:
app/hooks/use-theme.ts- Subscribes to ChatGPT theme viauseOpenAIGlobal('theme')- Applies
darkclass todocument.bodywhen theme is'dark' - Component calls
useTheme()to trigger synchronization
Component usage:
app/artifact/artifact-viewer.tsx- Wraps all content indata-artifact-container-chatgptdivs- All artifact widgets must follow this pattern for theme consistency
Storybook Alignment
Storybook previews sync ChatGPT theme CSS to match production behavior.
Sync mechanism:
apps/storybook/src/styles.cssimports@chatgpt-artifacts/chatgpt-app/artifact-theme.cssChatGPTPreviewcomponent'ssyncWidgetStylescallback mirrors all styles from Storybook document to widget iframe- Copies
<style>and<link rel="stylesheet">elements into widget iframe head - Mirrored styles tagged with
data-chatgpt-mirror="true"for cleanup on updates
Result: Storybook previews use identical CSS variables as production, ensuring visual parity.
See apps/storybook/.agents/docs/chatgpt-preview-system.md for Storybook preview architecture details.
Color Source
CSS variable values match ChatGPT Apps SDK design guidelines:
- Light mode: White backgrounds, dark text (
#0d0d0d), ChatGPT blue (#0285ff) - Dark mode: Dark gray backgrounds (
#212121), light text, same blue accents
Values intentionally align with platform design system for visual consistency across all ChatGPT widgets.
Upstream reference:
ChatGPT Apps SDK Design Guidelines Contains: Official color system specification (light/dark mode values), typography, spacing, component design patterns Read when: Verifying color values, understanding design system rationale, or implementing new visual components