Reputation: 4193
I am creating a directive which adjusts the class of the element that it is applied to. However, the styles for that class do not apply when the class changes. For instance:
Form.svelte
<form id='sign-in' use:delayed={ handleSubmit }>
<label for='sign-in-name'>Your Name</label>
<input required id='sign-in-name' type='text' />
<input type='submit' value='Sign In' />
</form>
<style>
form {
display: block;
}
form.submitting {
display: none;
}
</style>
Delayed.js
export default function(node, action) {
node.addEventListener('submit', async function(event) {
event.preventDefault()
const originalClass = node.className
node.className = `${ originalClass } submitting`
await action()
node.className = originalClass
})
}
In this case, the class will change successfully in the DOM, but the form will still display. The form.submitting
style doesn't even make it into the CSS generated by Svelte.
I know that I can work around this using a global stylesheet, but I'm curious why the scoped styles don't apply and if there's a way to make it work that way.
This works, but it feels hacky.
<style>
form {
display: block;
}
:global(form.submitting) {
display: none;
}
</style>
Upvotes: 0
Views: 1984
Reputation: 25041
Svelte compiler removes unused CSS rules, that is rules with selectors that do not match in the markup of the component. You should have a compiler warning "Unused CSS selector" about that. And since the compiler can't see dynamically added classes, your form.submitting
selector is removed.
The solution is indeed to make your dynamic selector :global(...)
.
If you want your style to only apply in the scope of this component and its children, you need a wrapping element that you can reference like such:
<div>
<form>...</form>
</div>
<style>
div :global(form.submitting) { ... }
</style>
Svelte will scope the div
part of the selector to the current component, effectively meaning that the :global(...)
part will only apply to the form inside a <div>
inside this component.
Upvotes: 5