Skip to main content

Often, you need to influence the styles inside a child component. Perhaps we want to make these boxes red, green and blue.

One way to do this is with the :global CSS modifier, which allows you to indiscriminately target elements inside other components:

App
<style>
	.boxes :global(.box:nth-child(1)) {
		background-color: red;
	}

	.boxes :global(.box:nth-child(2)) {
		background-color: green;
	}

	.boxes :global(.box:nth-child(3)) {
		background-color: blue;
	}
</style>

But there are lots of reasons not to do that. For one thing, it’s extremely verbose. For another, it’s brittle — any changes to the implementation details of Box.svelte could break the selector.

Most of all though, it’s rude. Components should be able to decide for themselves which styles can be controlled from ‘outside’, in the same way they decide which variables are exposed as props. :global should be used as an escape hatch — a last resort.

Inside Box.svelte, change background-color so that it is determined by a CSS custom property:

Box
<style>
	.box {
		width: 5em;
		height: 5em;
		border-radius: 0.5em;
		margin: 0 0 1em 0;
		background-color: var(--color, #ddd);
	}
</style>

Any parent element (such as <div class="boxes">) can set the value of --color, but we can also set it on individual components:

App
<div class="boxes">
	<Box --color="red" />
	<Box --color="green" />
	<Box --color="blue" />
</div>

The values can be dynamic, like any other attribute.

This feature works by wrapping each component in an element with display: contents, where needed, and applying the custom properties to it. If you inspect the elements, you’ll see markup like this:

<svelte-css-wrapper style="display: contents; --color: red;">
	<!-- contents -->
</svelte-css-wrapper>

Because of display: contents this won’t affect your layout, but the extra element can affect selectors like .parent > .child.

Edit this page on GitHub

1
2
3
4
5
6
7
8
9
<script>
	import Box from './Box.svelte';
</script>
 
<div class="boxes">
	<Box />
	<Box />
	<Box />
</div>