Skip to content
Design
Skill

/setting-up-charcoal-css-variables

Use before writing or editing any code that imports @charcoal-ui/react, and whenever a project's charcoal setup is unverified, incomplete or being finished. Charcoal components render completely unstyled unless BOTH @charcoal-ui/theme/css/v2/light.css is imported AND the

From plugin
charcoal
3787 skills

Claude Code

$ npx -y skills add pixiv/charcoal --skill setting-up-charcoal-css-variables --agent claude-code

SKILL.md

setting-up-charcoal-css-variables.SKILL.md
name: setting-up-charcoal-css-variables
description: Use before writing or editing any code that imports @charcoal-ui/react, and whenever a project's charcoal setup is unverified, incomplete or being finished. Charcoal components render completely unstyled unless BOTH @charcoal-ui/theme/css/v2/light.css is imported AND the .ch-token-v2 class is on <html>; importing dist/index.css alone, or adding the stylesheet without the class, silently produces correct geometry with no colors at all.

Setting up charcoal with CSS variables

The lowest-dependency way to use charcoal: load two stylesheets, add one class, then write `var(--charcoal-*)` anywhere.

Install

npm install @charcoal-ui/react@^6 @charcoal-ui/theme@^6 react-aria react-stately

Pin the major. Design Token 2.0 and the CSS layout below are v6; v5 and earlier differ. Keep every `@charcoal-ui/*` package on the same major.

Peer dependencies of `@charcoal-ui/react`: `react >=17.0.0`, `react-aria >=3.48.0`, `react-stately >=3.46.0`. The two react-aria packages are **not** installed for you. React 18 and 19 both satisfy the range.

Skip `@charcoal-ui/react` if you only want tokens — `@charcoal-ui/theme` alone is enough.

Load the CSS

// Load once at the app root.
import '@charcoal-ui/react/dist/index.css' // component implementation CSS
import '@charcoal-ui/theme/css/v2/light.css' // Design Token 2.0 — light
import '@charcoal-ui/theme/css/v2/dark.css' // Design Token 2.0 — dark

`dist/index.css` only _consumes_ `var(--charcoal-color-*)`. It never defines them.

The failure this causes is lopsided in a way that misleads people: **colors go through `var()`, but layout does not.** Padding, radius, font-size, and line-height are written as literal values, so they keep working. Load `dist/index.css` alone and you get a correctly shaped, correctly sized button with a transparent background and default black text. Nothing errors — an undefined custom property just makes that one declaration invalid, and the property falls back to its initial value.

If a charcoal component looks _structurally_ right but _colorless_, this is why.

Prefer `@charcoal-ui/react/dist/layered.css` over `dist/index.css` when you need to override charcoal styles from your own CSS. Its contents are wrapped in `@layer charcoal`, so any unlayered rule of yours wins without a specificity fight. It requires iOS 15.4+.

Opt in to Design Token 2.0 — required

Token 2.0 only applies inside `.ch-token-v2`.

<html class="ch-token-v2" lang="ja"></html>

The shipped selectors are:

/* light.css */
:root.ch-token-v2[data-theme='light'],
:root.ch-token-v2:not([data-theme]),
:root[data-theme='light'] .ch-token-v2,
:root:not([data-theme]) .ch-token-v2 {
  --charcoal-color-…: …;
}

/* dark.css */
:root[data-theme='dark'] {
  --charcoal-color-…: …;
}

Two consequences:

  • Without `.ch-token-v2`, **no light-theme rule matches** and every token is undefined.
  • Dark is scoped to `:root` only, so `data-theme="dark"` applies page-wide regardless of `.ch-token-v2`.

Put the class on `<html>`, or on an ancestor of the components you want themed. Variables inherit, so siblings are unaffected.

Use the tokens

.card {
  background-color: var(--charcoal-color-background-default);
  color: var(--charcoal-color-text-default);
  border: 1px solid var(--charcoal-color-border-secondary);
  border-radius: var(--charcoal-radius-s);
  padding: var(--charcoal-space-40);
}

Names follow `--charcoal-<category>-<semantic>-<state>`. Common ones: `color-text-default` / `-secondary-default` / `-tertiary-default`, `color-background-default` / `-secondary` / `-tertiary`, `color-border-default` / `-secondary`, `color-container-primary-default`, `radius-xs|s|m|l`, `space-*`. Read `node_modules/@charcoal-ui/theme/dist/css/v2/light.css` for the full list.

Components need no provider

import { Button } from '@charcoal-ui/react'

export const Save = () => <Button variant="Primary">保存</Button>

`Button` imports its own CSS and uses no context. Wrap in `CharcoalProvider` **only** when you use overlays (`Modal`, `DropdownSelector`) — it supplies react-aria's `SSRProvider` and `OverlayProvider`.

Theme switching

document.documentElement.dataset.theme = 'dark' // or 'light'

For SSR, run this before paint to avoid a flash:

import { makeSetThemeScriptCode } from '@charcoal-ui/react'

;<script dangerouslySetInnerHTML={{ __html: makeSetThemeScriptCode() }} />

Use `makeSetThemeScriptCode()`, not `<SetThemeScript />`. The component's props type requires both `localStorageKey` and `rootAttribute`, so `<SetThemeScript />` is a type error; `makeSetThemeScriptCode()` accepts zero arguments.

System theme does not follow the OS

`useThemeSetter()` **removes** `data-theme` when the user is on "system", by design — it expects CSS to handle `prefers-color-scheme`. Design Token 2.0's CSS has no `prefers-color-scheme` block, so with the attribute removed `:root:not([data-theme]) .ch-token-v2` matches and the page is **stuck on light** even on a dark OS.

Either always write an explicit `data-theme`, or add the missing bridge yourself:

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']).ch-token-v2,
  :root:not([data-theme='light']) .ch-token-v2 {
    /* copy the declarations from @charcoal-ui/theme/css/v2/dark.css */
  }
}

Mirror light.css's selector shape. Targeting bare `:root` fails when `.ch-token-v2` sits on a descendant: that descendant's own light values beat inherited dark values from an ancestor.

Common mistakes

| Mistake | Fix | | ---------------------------------- | ------------------------------------------------ | | Only `dist/index.css` loaded | Add `@charcoal-ui/theme/css/v2/{light,dark}.css` | | `.ch-token-v2` missing | Add it to `<html>` or an ancestor | | `<

Read more
@pixiv
Ships withcharcoal

This is the monorepo for the @charcoal-ui packages by pixiv.

Stars on GitHub

Momentum

stars in total
378
Star history of pixiv/charcoal on GitHub, a chart by star-history.com

Other skills on charcoal.

choosing-charcoal-styling

choosing-charcoal-styl…

Use before writing or editing any code that imports @charcoal-ui, and whenever a project's charcoal setup is unverified or…

@pixiv@pixivInstall Skill
choosing-charcoal-tokens

choosing-charcoal-toke…

Use before choosing any color, text style, spacing, radius or border value in code that uses @charcoal-ui, and whenever a literal…

@pixiv@pixivInstall Skill
implement-figma-design

implement-figma-design

Use when building a screen from a prepared Figma design pack — a design.md, a spec.json and an assets/ directory produced by…

@pixiv@pixivInstall Skill
prepare-figma-design

prepare-figma-design

Use when you have a figma.com link or a local .fig export, and someone needs to build that design — including when you will build…

@pixiv@pixivInstall Skill
setting-up-charcoal-styled

setting-up-charcoal-st…

Use before writing or editing code that uses @charcoal-ui with styled-components, TokenInjector, createTheme or addThemeUtils,…

@pixiv@pixivInstall Skill

More skills from other plugins.

impeccable

impeccable

Use to design, redesign, critique, audit, polish or animate a frontend: websites, landing pages, dashboards, app UI, components,…

@pbakaus@pbakausInstall Skill

Questions about setting-up-charcoal-css-variables.

Which coding agents can use setting-up-charcoal-css-variables?
setting-up-charcoal-css-variables installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.