Theme System

Full shadcn/ui theme compliance — 17 CSS variables, pair pattern, class-based dark mode.

Typography

Three fonts loaded via next/font/google. Chinese text automatically uses Noto Serif SC as a fallback.

Body — PT Serif (serif)

The quick brown fox jumps over the lazy dog. 0123456789

你好世界,这是一段中文内容。思源宋体

Headings — Ubuntu (sans-serif)

The quick brown fox jumps over the lazy dog.

你好世界,中文字体回退

Code — system monospace

const font = "Noto Serif SC"; // 代码块

Overview

This site uses shadcn/ui's theme pattern — the most popular design system for Next.js. Colors are defined as raw HSL triplets in CSS variables, mapped to Tailwind utilities. Theme = a class that sets variable values.

The core idea

Every color has a partner. --card is the background. --card-foreground is the text on that background. Variables hold the actual rendered color — no opacity modifiers needed in components.

Total variables
17
8 pairs + radius
Fixed (neutral)
3
destructive, radius
Theme (colored)
14
Change per theme

The Pair Pattern

shadcn/ui uses a naming convention: --{name} for background, --{name}-foreground for text on that background.

background / foreground
The page canvas and default text
What

--background is the deepest layer — the page itself. --foreground is the color of all text by default.

Why

Text must be readable on the page. White text on dark background = high contrast. This pair never changes because readability is non-negotiable.

How to use
bg-backgroundtext-foreground

This text uses text-foreground on bg-background.

card / card-foreground
Elevated surfaces and text on them
What

--card is the actual rendered surface color per theme — solid white in light mode, subtle dark in dark mode. Just use bg-card. The variable handles the rest. --card-foreground is the text on cards.

Why

Variables define the actual color, not a base to apply opacity to. This means components never need dark: prefixes — the variable changes when the theme class changes.

How to use
bg-cardtext-card-foreground

bg-card — adapts automatically per theme

popover / popover-foreground
Floating surfaces (dropdowns, tooltips, popovers)
What

--popover is the background for floating elements. Currently matches --card. --popover-foreground is text on popovers.

Why

Floating elements may need a different background than cards (e.g., darker in dark mode for more contrast). Separate variable allows this without affecting cards.

How to use
bg-popovertext-popover-foreground
primary / primary-foreground← main interactive
Buttons, toggles, active states
What

--primary is the main interactive color — buttons, toggles, active indicators. --primary-foreground is text on primary surfaces.

Why

primary is for interactive elements.accent is for decorative highlights. This semantic split means a future theme could use different colors for each.

How to use
bg-primarytext-primary-foreground

Primary button

Primary at 10%

secondary / secondary-foreground
Secondary buttons, less prominent actions
What

--secondary is a muted surface color for secondary actions. Less prominent than primary. --secondary-foreground is text on secondary surfaces.

Why

Not every button should be primary. Secondary provides a toned-down alternative for less important actions (Cancel, Skip, etc.).

How to use
bg-secondarytext-secondary-foreground
accent / accent-foreground← decorative
Decorative highlights, code syntax, emphasis
What

--accent is for decorative highlights — code syntax, category pills, subtle emphasis. Not for interactive elements. --accent-foreground is text on accent surfaces.

Why

Separating accent from primary means decorative colors can change independently of interactive colors. A theme could use rose for accent but blue for primary.

How to use
bg-accentbg-accent/10text-accent-foreground
ring
Focus indicators and active rings
What

--ring is the color for focus rings and active state indicators. Set to foreground color for maximum visibility.

Why

Focus rings must be visible on any background. Using the foreground color ensures contrast. ring-accent is for decorative rings, ring is for accessibility.

How to use
ringring-2 ringfocus-visible:ring-2 focus-visible:ring
muted / muted-foreground
Subdued elements and secondary text
What

--muted is stone-800 — slightly lighter than the page background. --muted-foreground is gray — dimmer than default text.

Why

Not everything should be equally prominent. Muted creates visual hierarchy — secondary info (dates, labels, code blocks) recedes while primary content stands out.

How to use
bg-mutedtext-muted-foreground

This is muted-foreground on muted background — secondary info.

destructive / destructive-foreground
Error states and dangerous actions
What

--destructive is red — universally understood as danger. --destructive-foreground is near-white — text on red.

Why

Red = danger is a universal convention. Changing it per theme would confuse users. If the theme is blue, destructive actions should still be red — not blue.

How to use
bg-destructivetext-destructive-foreground
border / input
Separators and form controls
What

--border and --input define the color for borders and form controls. Use border-border or border-input.

Why

Borders should be barely visible — they create structure without drawing attention. White at 10% opacity is subtle but visible on dark backgrounds.

How to use
border-border/10border-input/10
border-border/10

Fixed vs Theme Variables

Fixed variables are always neutral. Theme variables change per theme — they carry the site's identity.

Fixed (neutral)

These form the foundation. Always neutral so text is always readable.

background / foreground
card / card-foreground
popover / popover-foreground
muted / muted-foreground
border / input
destructive / destructive-foreground
Theme (colored)← the personality

These define the site's color identity. Change --accent and --primary to swap the entire feel.

primary— interactive elements
secondary— secondary actions
accent— decorative highlights
ring— focus indicators
To change theme:
--primary: 356 89% 60%; /* rose */

Usage Guide

Each variable has a clear role. Use the right one for the right context.

1. Primary Buttons
Use bg-primary + text-primary-foreground for main actions.
2. Secondary Buttons
Use bg-secondary + text-secondary-foreground for less prominent actions.
3. Focus Ring (accessibility)
Use ring for keyboard focus indicators. Uses --ring (foreground-based) for maximum visibility.
4. Decorative Accent
Use bg-accent for decorative highlights — code syntax, category pills, subtle emphasis. Not for interactive elements.
Decorative highlight
5. Destructive Actions
Use bg-destructive + text-destructive-foreground. Red = danger is universal — never changes per theme.

Color Palette

background
foreground
card
card-foreground
popover
popover-fg
primary
primary-fg
secondary
secondary-fg
muted
muted-foreground
accent
accent-foreground
destructive
destructive-fg
border
input
ring

Button Examples

Theme Colors

The site uses Terracotta (light) and Rose (dark) as the primary/accent colors. Change --primary and --accent in globals.css to swap the entire feel.

Terracotta
--primary: 20 48% 53%
Rose
--primary: 356 89% 60%

Quick Reference

VariableTailwindUse forChanges?
--backgroundbg-backgroundPage canvasTheme
--foregroundtext-foregroundDefault textTheme
--cardbg-cardCard surfacesTheme
--card-foregroundtext-card-foregroundText on cardsTheme
--popoverbg-popoverFloating surfacesTheme
--popover-foregroundtext-popover-foregroundText on popoversTheme
--primarybg-primaryButtons, interactiveTheme
--primary-foregroundtext-primary-foregroundText on primaryTheme
--secondarybg-secondarySecondary actionsTheme
--secondary-foregroundtext-secondary-foregroundText on secondaryTheme
--mutedbg-mutedSubtle backgroundsTheme
--muted-foregroundtext-muted-foregroundSecondary textTheme
--accentbg-accentDecorative highlightsTheme
--accent-foregroundtext-accent-foregroundText on accentTheme
--destructivebg-destructiveErrors, dangerFixed
--destructive-foregroundtext-destructive-foregroundText on errorsFixed
--borderborder-borderBordersTheme
--inputborder-inputForm controlsTheme
--ringringFocus indicatorsTheme
--radiusrounded-lgBorder radiusFixed