Styling is half of UI work, and Svelte's scoping rules decide which selectors actually apply.
Styles in a component's <style> block are scoped: Svelte adds a hashed class to the elements in this component and to your selectors. Consequences:
- Selectors only match elements written in this component's markup, not elements rendered by child components or inserted with
{@html}. - Unused selectors produce a compiler warning and are removed.
- Escape scoping with `:global(...)`, e.g.
.card :global(p)to style paragraphs inside children, or a:global { ... }block.
For dynamic classes, the `class` attribute accepts objects and arrays (Svelte 5.16+, using clsx rules): class={['btn', { active, disabled: !enabled }, size]}. Truthy object keys are added, falsy values are skipped. The older `class:name={cond}` directive still works, with shorthand class:active.
`style:prop={value}` sets one inline style property: style:color={color}, style:--progress="{pct}%"; add |important if needed.
To let parents theme a child without breaking scoping, use CSS custom properties. The child uses var(--accent, tomato); the parent passes <Slider --accent="purple" />, which Svelte applies on a wrapper element.
You can still use Tailwind, CSS modules or global stylesheets; scoped styles are simply the default for component-specific CSS.
Example
<script>
let active = $state(true);
let size = $state('lg');
let pct = $state(40);
</script>
<button class={['btn', size, { active }]} onclick={() => (active = !active)}>
Toggle <!-- class="btn lg active" -->
</button>
<div class="bar" style:--pct="{pct}%"></div>
<div class="content">{@html '<p>from html</p>'}</div>
<style>
.btn { padding: 0.5rem 1rem; }
.btn.active { background: var(--accent, #d63a0f); color: white; }
.lg { font-size: 1.25rem; }
.bar { width: var(--pct); height: 4px; background: green; }
.content :global(p) { margin: 0; } /* reaches into {@html} content */
</style>Remember
- Component CSS is scoped;
:global(...)opts out for specific selectors class={[..., { name: cond }]}handles conditional classes;class:still worksstyle:propand CSS custom properties pass dynamic values and theming
Watch out for
- Styling a child component's elements from the parent with plain selectors; scoping prevents it, use :global or custom properties.