CSS hooks

Theme CSS should target these data-pc attributes, not Tailwind classes or DOM structure. The attributes are a stable interface. Class names and markup can change in any release; a data-pc hook is only renamed or removed with a note in the changelog.

Most hooked elements also carry data-pc-tokens, a space-separated list of the token ids their default styling uses (for example data-pc-tokens="overlay border.strong fg.dim shadow.popover" on a menu). It is informational: the Theme Editor's element picker reads it to jump from a clicked element to the tokens that color it. Don't style against it; target data-pc instead.

HookElementUseful attributes
[data-pc="topbar"]The top bar
[data-pc="panel"]Left and right side panels, and the theme editordata-side="left" / "right"
[data-pc="rail"]The icon tab strip beside a side paneldata-side="left" / "right"
[data-pc="rail-button"]A tab in a rail (role="tab")aria-selected="true" on the open tab (was aria-pressed before rails became a real tablist)
[data-pc="toolbar"]Floating toolbars (the bottom tool dock)
[data-pc="tool"]A button in a floating toolbardata-active="true" for the selected tool, data-primary="true" for call-to-action buttons
[data-pc="doc-title"]The file name in the top bar
[data-pc="canvas-frame"]The box around the canvas viewport (not shown while presenting)Decorate with ::before / ::after and pointer-events: none
[data-pc="popover"]Dropdown menus and flyouts (fill, text/effect/grid styles, type details, pixel swatches)
[data-pc="dialog"]Modal dialogs[data-pc="dialog-backdrop"] is the dimmed layer, [data-pc="dialog-title"] the heading
[data-pc="list-row"]Selectable rows in style, asset and version listsaria-selected="true"
[data-pc="layer-row"]A row in the layers or pages paneldata-selected="true"
[data-pc="section"]A collapsible property-panel section
[data-pc="section-header"]A section's collapse button (title, chevron, badge)
[data-pc="section-title"]A section's title text
[data-pc="label"]Small field captions
[data-pc="input"]The box around text, number and select fields:focus-within; data-variant="bare" for in-place edit fields
[data-pc="select"]A native select inside an input box
[data-pc="button"]Text buttonsdata-variant="primary" / "secondary" / "ghost" / "danger"
[data-pc="icon-button"]Icon-only buttonsaria-pressed="true" when active
[data-pc="segmented"]Segmented controls (Flow, alignment…)Segments are [role="radio"] with aria-checked
[data-pc="tabs"] / [data-pc="tab"]Tab strips and their tabsaria-selected="true"
[data-pc="switch"]Toggle switchesaria-checked
[data-pc="checkbox"]Checkbox boxes
[data-pc="slider"]Range sliders (wrapper around the native range input)
[data-pc="slider-field"]A label + slider + number row
[data-pc="badge"]Status badgesdata-tone
[data-pc="menu-item"]Rows in dropdown and context menusaria-checked on checkable items
[data-pc="option-bar"]Secondary floating bars: brush options, the PopCorn timer, the pixel timelinedata-kind="timer" / "timeline"; centred with the translate property, so animate scale/rotate only
[data-pc="toolbar-divider"]Separators inside toolbars
[data-pc="canvas-hint"]The instruction pill at the top of the canvas
[data-pc="floating-panel"]Floating PopCorn panels (voting)
[data-pc="timer-digits"]The PopCorn timer readoutdata-done="true" when time is up
[data-pc="file-browser"]The full-screen file browser
[data-pc="file-card"]A file in the file browserdata-current="true" for the open file
[data-pc="app-logo"]The logo mark in the file browser header
[data-pc="shortcuts-panel"] / [data-pc="kbd"]The keyboard shortcuts panel and its key caps
[data-pc="empty-state"]"No layers yet" / "No files yet" messages
[data-pc="avatar"]Collaborator avatars in the top bar
[data-pc="resizer"]Side panel resize handles
[data-pc="brush-preview"]Brush stroke thumbnails
[data-pc="desktop-tabs"]Desktop app: the tab strip rowA separate page; body.home-active while Home is open (the strip is see-through over file tabs)
[data-pc="desktop-tab"]Desktop app: a tab.active, .pinned (Home)
[data-pc="desktop-tab-close"] / [data-pc="desktop-tab-new"]Desktop app: a tab's close button and the new-tab button

On <html>:

  • data-theme is the active theme id.
  • data-theme-type is dark or light.
Restyle the toolbar with a CSS hook · 0:07
Description

A copy of PopCraft Dark in the theme editor. On the CSS tab a rule is typed for the [data-pc="tool"] hook — round tool buttons with an outline — and the toolbar under the canvas changes as it is typed.

Desktop tab strip

In the desktop app the tab strip is its own page. The editor sends it the same stylesheet it applies (token variables and theme CSS), so desktop-* hooks style it like any other element. Only token variables, not web fonts, are available there.

Canvas background

The canvas is drawn on the GPU, so theme CSS can't put anything behind your artwork (CSS over the canvas would cover it). Use the canvas.backdrop.dots and canvas.backdrop.dotsAlt tokens for a halftone backdrop drawn under all content; see the token reference.

Decorating containers

topbar and panel hold dropdown menus that are positioned inline. Don't give them isolation, z-index, transform, rotate or scale — each of those creates a stacking context that traps the menus underneath the neighbouring panels. To draw decoration behind their content, use a single ::before and lift the children above it, the way the built-in comic themes do:

[data-pc="panel"] > :not([class*="absolute"]) { position: relative; }
[data-pc="panel"]::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: radial-gradient(circle, var(--pc-decor-pop1) 2px, transparent 2.6px);
  background-size: 12px 12px;
  mask-image: linear-gradient(to bottom, #000, transparent 50%);
}

Images in theme CSS must be data: URLs (quoted or not); anything else is replaced with none. SVG masks colored by background: var(--pc-…) are a handy way to draw token-colored shapes such as starbursts.

Example

/* Pill buttons with a hard shadow that press down */
[data-pc="button"] {
  border-radius: 999px;
  box-shadow: 3px 3px 0 var(--pc-border);
}
[data-pc="button"]:active {
  transform: translate(2px, 2px);
  box-shadow: none;
}
 
/* Halftone dots on the side panels */
[data-pc="panel"] {
  background-image: radial-gradient(circle, rgba(0, 0, 0, 0.08) 1.5px, transparent 2px);
  background-size: 10px 10px;
}
 
/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
  [data-pc="button"]:active { transform: none; }
}