Skip to content

A way to declare a scoped class for the CSS compiler (ex use:class) #8345

@adiguba

Description

@adiguba

Describe the problem

Svelte's CSS scoping is great and allow to avoids a lot of mistakes/conflicts.

But it is logically limited to the class attribute and the class: directive.
Obviously the CSS compiler can't detect classes defined outside of these attribute/directive...

It cannot detect:

  • The classes set inside an use:action.
  • The classes set via the DOM (for ex. via an external library).

And in this case, we got the famous warning "Unused CSS selector" :

<div class="btn" use:anActionThatCanAddClasses>
	...
</div>

<style>
	.btn {
		background: blue;
	}

	/* WARNING : Unused CSS selector */
	.important { 
		background: red;
		border: 3px solid black;
	}
</style>

The actual solution is to use the :global(...) modifier, but if it's misused it can break the scoping and have non-intuitive behavior on the selector specificity.

Example :

	.btn {
		background: blue;
	}

	/* NO warning, but
		- style is not scoped, and can affect other nodes
		- some properties are not applied, as the class ".important"
		  is less relevant than the ".btn.svelte-XXXX" scoped CSS.
 	*/
	:global(.important) { 
		background: red; /* NOT applied */
		border: 3px solid black;
	}

The correct way to do this is to bundle the scoped and global CSS , like this :

	.btn:global(.important) { 
		...
	}

But it's verbose and not intuitive.

Describe the proposed solution

It should be possible to declare classes that "could" be added to a node.

This would only serve the CSS compiler and would have no impact on the generated JavaScript code.

I think we could give a special meaning to the use:class="names" directive.
It's a non-breaking change as class is a keyword, and so it cannot be used as an action.

So use:class="names" could be a special case, which would expect a string containing the class names (like a normal class attribute).

Ex:

<div class="btn" use:class="important"> ... </div>

Which means that this <div> only has the "btn" class, but it can have the "important" class.

The CSS compiler would use this in addition to the class attribute/directive to determine the scope of CSS rules, which will avoids the need of :global.

Example :

<div class="btn" use:class="important" use:anActionThatCanAddClasses>
	...
</div>

<style>
	.btn {
		background: blue;
	}
	/* It just work ! */
	.important { 
		background: red;
		border: 3px solid black;
	}
</style>

Alternatives considered

continue to use :global()

Importance

nice to have

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions