بنقرة واحدة
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