A spin-off from UnoCSS that allows for full-featured scoped utility classes by component.
Read the svelte-scoped-uno setup instructions to scope utility classes by component.
Alternatively, use svelte-preprocess-unocess in contexts where Vite plugins don't work, like svelte-package
. Anything discussed below regarding a global stylesheet will have no bearing on this package.
SvelteKit
example in examples/sveltekit-vite-pluginVite-Svelte
example in examples/svelte-vite-plugin.SvelteKit Library
example in examples/sveltekit-preprocessPlace utility styles right inside of each component's style block instead of in a global uno.css
file. Class names will be compiled to unique names so they will conflict nowhere and work everywhere. So classes that depend are interdependent with other components will just work. You can use rtl:mr-1
or dark:text-white
which rely on dir="rtl"
or .dark
being defined in a parent component. You can pass classes to children components as long as you pass them using a prop named class
, e.g. class="text-lg bg-red-100"
. Spacing out children <Button>
components using .space-x-2
will also work.
Read more about Why?
Before:
<div class="w-full mb-1" />
After:
<div class="uno-3hashz" />
<style>
:global(.uno-3hashz) {
width: full;
margin-right: .25rem;
}
</style>
<div class="ltr:left-0 rtl:right-0"></div>
turns into:
<div class="uno-3hashz"></div>
<style>
:global([dir="ltr"] .uno-3hashz) {
left: 0rem;
}
:global([dir="rtl"] .uno-3hashz) {
right: 0rem;
}
</style>
If an element in your component wants to add space between 3 children elements of which some are in separate components you can now do that:
<div class="space-x-1">
<div>Status</div>
<Button>FAQ</Button>
<Button>Login</Button>
</div>
turns into:
<div class="uno-7haszz">
<div>Status</div>
<Button>FAQ</Button>
<Button>Login</Button>
</div>
<style>
:global(.uno-7haszz > :not([hidden]) ~ :not([hidden])) {
--un-space-x-reverse: 0;
margin-left: calc(0.25rem * calc(1 - var(--un-space-x-reverse)));
margin-right: calc(0.25rem * var(--un-space-x-reverse));
}
</style>
You can add the class
prop to a component which which places them on to an element using class="{$$props.class} foo bar"
.
<Button class="px-2 py-1">Login</Button>
turns into:
<Button class="uno-4hshza">Login</Button>
<style>
:global(.uno-4hshza) {
padding-left:0.5rem;
padding-right:0.5rem;
padding-top:0.25rem;
padding-bottom:0.25rem;
}
</style>
class:
syntaxClass names added using Svelte's class directive feature, class:text-sm={bar}
, will also be compiled. No need to add extractorSvelte
. Custom extractors will not be used by this mode.
<div class:text-sm={bar}>World</div>
turns into:
<div class:uno-2hashz={bar}>World</div>
<style>
:global(.uno-2hashz) {
font-size: 0.875rem;
line-height: 1.25rem;
}
</style>
The class directive shorthand usage of class:text-sm
where text-sm
is both a class and a variable is also supported. The plugin will change class:text-sm
into class:uno-2hshza={text-sm}
.
<span class:logo />
<!-- This would work if logo is set as a shortcut in the plugin settings and it is a variable in this component -->
<div class="bg-red-100 text-lg">Hello</div>
<div class:text-sm={bar}>World</div>
<div class:text-sm>World</div>
<div class="fixed flex top:0 ltr:left-0 rtl:right-0 space-x-1 foo">
<div class="px-2 py-1">Logo</div>
<Button class="py-1 px-2">Login</Button>
</div>
<style>
div {
--at-apply: text-blue-500 underline;
}
.foo {
color: red;
}
</style>
will be transformed into this:
<span class:uno-0hashz={logo} />
<div class="uno-1hashz">Hello</div>
<div class:uno-2hashz={bar}>World</div>
<div class:uno-2hashz={text-sm}>World</div>
<div class="uno-3hashz foo">
<div class="uno-4hashz">Logo</div>
<Button class="uno-4hashz">Login</Button>
</div>
<style>
:global(.uno-1hashz) {
--un-bg-opacity: 1;
background-color: rgba(254, 226, 226, var(--un-bg-opacity));
font-size: 1.125rem;
line-height: 1.75rem;
}
:global(.uno-2hashz) {
font-size: 0.875rem;
line-height: 1.25rem;
}
:global(.uno-3hashz) {
position: fixed;
display: flex;
}
:global([dir="ltr"] .uno-3hashz) {
left: 0rem;
}
:global([dir="rtl"] .uno-3hashz) {
right: 0rem;
}
:global(.uno-3hashz > :not([hidden]) ~ :not([hidden])) {
--un-space-x-reverse: 0;
margin-left: calc(0.25rem * calc(1 - var(--un-space-x-reverse)));
margin-right: calc(0.25rem * var(--un-space-x-reverse));
}
:global(.uno-4hashz) {
padding-left:0.5rem;
padding-right:0.5rem;
padding-top:0.25rem;
padding-bottom:0.25rem;
}
:global(.uno-0hashz) {
/* logo styles will be put here... */
}
div {
--un-text-opacity: 1;
color: rgba(59, 130, 246, var(--un-text-opacity));
text-decoration-line: underline;
}
.foo {
color: red;
}
</style>
When this reaches the Svelte compiler, it will remove the :global() wrappers, and add it's own scoping hash just to the div
and .foo
rules.
By default UnoCSS leaves style resetting up to each user but they do provide some convenient reset options. Since that SvelteKit provides no convenient main.ts
sort of location where styles can be guaranteed to come first you either must manually place these into the head of app.html
as seen in sveltekit-preprocess's app.html
file or you easily add them at the beginning of svelte-scoped-uno's global styles using the injectReset
option.
// vite.config.ts
// ...
plugins: [
SvelteScopedUno({
+ injectReset: "@unocss/reset/tailwind.css"
}),
sveltekit(),
],
Preflights and safelist classes will be added to the global styles import in your <head>
tag as outlined in the svelte-scoped-uno setup instructions.
Do to the unique nature of having a few necessary styles in a global stylesheet and everything else contained in each component where needed (kind of like Svelte itself), presets need to be handled on a case-by-case basis:
@unocss/preset-typography
adds a large amount of complex styles to the .prose
class which svelte-scoped
will not properly surround with :global()
wrappers so add the prose
class to your safelist is using this preset. All other classes from this preset like prose-pink
will work fine like any other utility class as it just adds color variables. @unocss/preset-icons
works@unocss/web-fonts
workssvelte-scoped
uses its own extraction and compilation pipelineclass="..."
usage they will probably not work. If they add complicated styles like see in typography's .prose
then you probably need to place certain class names into your safelist.class="mb-1 mr-1"
will turn into something like class="_mb-1_9hwi32 _mr-1_84jfy4
. In production, these will be compiled into a single class name using your desired prefix, uno-
by default, and a hash based on the filename + class names, e.g. class="uno-84dke3
.class="mr-1"
type of strings defined inside comments but it doesn'tsvelte-scoped
mode of the UnoCSS Vite plugin, but was extracted into a separate plugin as it was not able to benefit from much of the UnoCSS ecosystem without specialized code due to using component scoping. It was becoming too difficult too maintain in that location and was diverging more and more from the standard UnoCSS use case..prose
, etc) into the <head>
tag before Svelte component styles are added.