Skip to content
Design
Skill

/setting-up-charcoal-styled

Use before writing or editing code that uses @charcoal-ui with styled-components, TokenInjector, createTheme or addThemeUtils, and whenever such a project's charcoal setup is unverified or incomplete.

From plugin
charcoal
3787 skills

Claude Code

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

SKILL.md

setting-up-charcoal-styled.SKILL.md
name: setting-up-charcoal-styled
description: Use before writing or editing code that uses @charcoal-ui with styled-components, TokenInjector, createTheme or addThemeUtils, and whenever such a project's charcoal setup is unverified or incomplete.

Setting up charcoal with styled-components

`@charcoal-ui/styled` exists for codebases already written in styled-components. Read the next section before wiring it in.

Choose this only for existing code

`@charcoal-ui/styled` is **frozen at Design Token 1.0**. Its source contains no reference to Token 2.0, and it receives only maintenance commits while `@charcoal-ui/tailwind-config` keeps gaining v2 features.

The package is not formally deprecated — only `createTheme` carries `@deprecated`. The problem is not that it is forbidden; it is that it cannot reach the current token generation.

It also drags in the component library: `@charcoal-ui/styled` peer-depends on `@charcoal-ui/react`, because `useTheme`, `useThemeSetter`, `themeSelector`, and `SetThemeScript` are re-exports whose implementations live there. You get that dependency even if you never render a charcoal component.

For a new project, or when you only want tokens, use setting-up-charcoal-css-variables instead.

Install

npm install @charcoal-ui/styled@^6 @charcoal-ui/theme@^6 @charcoal-ui/react@^6

Pin the major and keep every `@charcoal-ui/*` package on the same one. `styled-components >=5.1.1` and `react >=17.0.0` are peers.

Provider

Two independent mechanisms, both usually needed:

  • `ThemeProvider` (styled-components) supplies the **JS theme object** so `${({ theme }) => theme.color.text1}` resolves. The values are literal hex strings, not `var()`.
  • `TokenInjector` (`@charcoal-ui/styled`) emits `--charcoal-color-*` **CSS variables** at runtime via `createGlobalStyle`, for anything not going through styled-components.
import { ThemeProvider } from 'styled-components'
import {
  TokenInjector,
  addThemeUtils,
  useTheme,
  useThemeSetter,
  themeSelector,
} from '@charcoal-ui/styled'
import { light, dark } from '@charcoal-ui/theme'

const lightTheme = addThemeUtils(light)
const darkTheme = addThemeUtils(dark)

export function ThemeRoot({ children }: { children: React.ReactNode }) {
  const [mode] = useTheme()
  useThemeSetter()

  return (
    <ThemeProvider theme={mode === 'dark' ? darkTheme : lightTheme}>
      <TokenInjector
        theme={{ ':root': light, [themeSelector('dark')]: dark }}
        background="background1"
      />
      {children}
    </ThemeProvider>
  )
}

`TokenInjector`'s optional `background` prop takes any key of `theme.color` (`background1`, `background2`, `surface1`…) and paints it as the page background on each selector.

Because the JS objects hold literal colors, switching themes requires swapping `ThemeProvider`'s `theme` prop. Rewriting CSS variables alone does not change `${({ theme }) => …}` output. The two systems must be kept in sync — that is what `useTheme` plus `useThemeSetter` do here.

Types

// styled.d.ts
import 'styled-components'
import type { CharcoalTheme } from '@charcoal-ui/theme'
import type { CharcoalThemeUtils } from '@charcoal-ui/styled'

declare module 'styled-components' {
  export interface DefaultTheme extends CharcoalTheme, CharcoalThemeUtils {}
}

Writing components

Use styled-components' own theming. Do **not** use `createTheme` / `theme(o => [...])` — it is `@deprecated` for runtime performance ([PR #377](https://github.com/pixiv/charcoal/pull/377)).

const Card = styled.div`
  background-color: ${({ theme }) => theme.color.background1};
  color: ${({ theme }) => theme.color.text1};
  border-radius: ${({ theme }) => theme.borderRadius[8]}px;
  ${({ theme }) => theme.utils.padding(16)}
  ${({ theme }) => theme.utils.typography(16)}
`

`addThemeUtils()` adds `theme.utils`: `margin*`, `padding*`, `gap`, `typography`, `focusVisibleFocusRingCss`, `assertiveRingCss`, `disabledCss`.

Constraints worth knowing before you hit them:

  • `theme.utils.typography(size)` accepts only `12 | 14 | 16 | 20`. **32 is not supported** — expand it by hand. `theme.typography.size[n]` is `{ fontSize: number; lineHeight: number }` in px, keyed by `12 | 14 | 16 | 20 | 32`:
  font-size: ${({ theme }) => theme.typography.size[32].fontSize}px;
  line-height: ${({ theme }) => theme.typography.size[32].lineHeight}px;
  • `theme.utils.margin` / `padding` accept only the spacing scale (`0, 4, 8, 16, 24, 40, 64, 104, 168, 272, 440`) or `'auto'`. Arbitrary px values are rejected by the type.
  • `theme.spacing` and `theme.typography` are identical in light and dark.

Theme switching and SSR

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

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

Prefer `makeSetThemeScriptCode()` over `<SetThemeScript />`; the component's props type requires both `localStorageKey` and `rootAttribute`.

Migrating off, in dependency order

You do not have to leave in one step.

1. **Drop `createTheme`.** The only `@deprecated` API here. Move to plain `${({ theme }) => theme.color.*}` or `addThemeUtils`. 2. **Drop `TokenInjector`.** Import `@charcoal-ui/theme/css/v2/{light,dark}.css` instead — static CSS supplies the same variables with no runtime `createGlobalStyle`. This is also the step that unlocks Design Token 2.0. 3. **Drop `ThemeProvider`.** Replace `theme.color.text1` reads with `var(--charcoal-color-text-default)`. 4. **Drop styled-components** if you want. By this point charcoal no longer cares.

If you only render `@charcoal-ui/react` components, steps 1–3 are already unnecessary — since v4 it does not depend on styled-components at all.

Common mistakes

| Mistake | Fix | | ----------------------------------------------- | -----------------------------------

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

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-styled.

Which coding agents can use setting-up-charcoal-styled?
setting-up-charcoal-styled 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.