ワンクリックで
scoped-styles
Use when authoring component stylesheets with automatic CSS scoping to a single component.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use when authoring component stylesheets with automatic CSS scoping to a single component.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Use when turning a Claude Design (or any mockup/design) into a well-structured pocopine app — choosing app architecture (a store plus layout/leaf components), translating inline styles into Pine Stylekit, wiring icons and resizable regions, and verifying the result.
Use when working with the pocopine Pine icons feature — the `icon!` proc macro for compile-time Rust SVG embedding, or the `<pine-icon>` template primitive with `register_icons!` for tree-shaking-friendly template rendering.
Use when building styles with Pine Stylekit, the Pocopine-native utility-CSS compiler, or working with @theme tokens and CSS generation in Rust/WASM projects
Use when building enter/leave transitions, layout animations, stagger effects, or spring-physics motion in pocopine components
Use when implementing authentication in pocopine apps — JWT verification, credentials, OAuth providers, session management, or guards
Use when defining background jobs, enqueueing work, configuring workers, or troubleshooting job execution in pocopine apps
| name | scoped-styles |
| description | Use when authoring component stylesheets with automatic CSS scoping to a single component. |
Scoped styles automatically isolate a component's CSS to that component's template using data-attributes, preventing style leaks and collisions. They are the default when you associate a .css file with a #[component].
styles.css) while keeping component rules isolated.[data-theme="dark"] and CSS custom properties for dark mode.body.dark or html).#[component(template = "Component.poco", style = "Component.css")]
style = "..." (optional): path to a .css file, relative to the .rs file.style is provided, the default is inferred as <StructName>.css.style is set; there is no scoped = true/false flag.:global())Use :global(selector) inside a scoped stylesheet to prevent scoping on a single rule:
/* This rule stays global — not scoped. */
:global(body.dark) .wrapper { background: #000; }
/* These rules are scoped with [data-pp-HASH]. */
.button { padding: 0.5rem; }
.button:hover { background: var(--brand-soft); }
Define tokens in a global styles.css at the app root:
:root {
--brand: #f8ae45;
--fg: #3d2415;
--bg: #fffaf2;
--radius: 8px;
}
[data-theme="dark"] {
--fg: #f5ead3;
--bg: #1a130c;
}
Then reference them in scoped component CSS without modification:
.card { background: var(--bg); border-radius: var(--radius); }
.card:hover { background: var(--bg-hover); }
The compiler (via #[component] expansion in pocopine-macros):
H = hash("component-name") → first 8 hex chars.data-pp-<H> to every element.[data-pp-<H>] to every selector's last compound (the rightmost class or element).Example with component site-header and hash a1b2c3d4:
Input CSS:
.site-header { position: sticky; }
.site-header-search { flex: 1; }
:global(body.dark) .wrapper { background: #000; }
Output CSS after scoping:
.site-header[data-pp-a1b2c3d4] { position: sticky; }
.site-header-search[data-pp-a1b2c3d4] { flex: 1; }
body.dark .wrapper { background: #000; } /* :global() unscoped */
Template with data-attributes:
<div pp-data="site-header" class="site-header" data-pp-a1b2c3d4>
<button class="site-header-search" data-pp-a1b2c3d4>Search</button>
</div>
File: src/components/site_header/mod.rs
#[derive(Default, Serialize, Deserialize)]
#[component(
template = "SiteHeader.poco",
style = "site_header.css",
role = "panel"
)]
pub struct SiteHeader {
pub theme: String,
}
#[handlers]
impl SiteHeader {
pub fn toggle_theme(&mut self) {
self.theme = if self.theme == "dark" { "light" } else { "dark" }.into();
}
}
File: src/components/site_header/site_header.css (automatically scoped)
.site-header {
position: sticky;
top: 0;
z-index: 5;
padding: 0.5rem 0;
background: color-mix(in srgb, var(--bg) 88%, transparent);
backdrop-filter: blur(10px);
}
.site-header-theme {
width: 1.9rem;
height: 1.9rem;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--fg);
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius);
cursor: pointer;
transition: background 0.12s;
}
.site-header-theme:hover { background: var(--bg-subtle); }
:global() for app-level stylesFile: src/components/tutorial/tutorial.css
.tutorial { padding: 2.5rem 0; }
.tutorial h2 { font-size: 1.75rem; text-align: center; }
.step-num {
width: 2.2rem;
height: 2.2rem;
border-radius: 50%;
background: var(--brand);
color: var(--brand-fg);
display: inline-flex;
align-items: center;
justify-content: center;
font-weight: 700;
}
/* Opt out: style body-level state at the app root. */
:global([data-tutorial-shown]) .tutorial { display: none; }
File: styles.css (global, app root)
:root {
--fg: #3d2415;
--bg: #fffaf2;
--brand: #f8ae45;
--border: #e5d3b0;
}
[data-theme="dark"] {
--fg: #f5ead3;
--bg: #1a130c;
--border: #3a2a1a;
--brand: #f8ae45; /* Preserved in dark mode */
}
File: src/components/showcase_card/showcase_card.css (component)
.showcase-card {
border: 1px solid var(--border);
background: var(--bg);
border-radius: var(--radius);
}
.showcase-tab[data-active="true"] {
background: var(--brand);
color: var(--brand-fg);
}
The component CSS automatically adapts to dark mode because it reads the CSS variables from :root — no per-component dark-mode duplication needed.
A cross-component selector like .parent .child in Parent.css targeting a .child inside an imported <child-component> will not work under scoping because each gets a different hash suffix. Use :deep(.child) instead (future feature) or refactor to avoid the cross-component dependency.
:root, html, body are never scopedThese pseudo-elements are exempt from scoping by design (they appear on a global allowlist). If you need a rule scoped to a component that affects body, use :global() explicitly.
:before, :after)The attribute is appended to the element part, not the pseudo-element:
/* Input */
button::before { content: "►"; }
/* Output (scoped with data-pp-HASH) */
button[data-pp-a1b2c3d4]::before { content: "►"; }
@keyframes namingAnimation names are automatically renamed to avoid collisions:
/* Input: two components both define 'spin' */
@keyframes spin { from { transform: rotate(0); } to { transform: rotate(360deg); } }
.loader { animation: spin 1s linear infinite; }
/* Output: renamed to keyframes-a1b2c3d4, reference updated */
@keyframes keyframes-a1b2c3d4 { ... }
.loader[data-pp-a1b2c3d4] { animation: keyframes-a1b2c3d4 1s linear infinite; }
:global() around class names:global() applies to selectors, not class values in HTML:
/* ✓ Correct: global selector */
:global(body.dark) .card { background: #000; }
/* ✗ Wrong: won't work as intended */
:global(.card) { background: #000; } /* This still gets scoped; use without :global() */
lightningcss handles edge casesThe scoper uses lightningcss (not regex), so it correctly handles attribute selectors with commas and special characters:
/* These work correctly even with special chars */
input[data-state="active,focus"] { border-color: var(--brand); }
[aria-label*="danger"] { color: var(--destructive); }
/rfcs/rfc-001-components.md § 5.5 (Component style format and scoping spec)/docs/poco/03-scoped-styles.md (detailed scoping algorithm and edge cases)crates/pocopine-macros/src/lib.rs (parses style = "..." and emits scoping pass)examples/website/src/components/ — real components using scoped CSS with global variables (SiteHeader, Tutorial, ShowcaseCard)examples/website/styles.css — root CSS with @theme-style tokens and [data-theme="dark"] theming