-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Passing class to components #2870
Comments
Modular CSS works fine with svelte3, we already use it in daily development. |
@tivac probably not the best place for this, but i tried to setup modular-css with rollup in sapper. Readme seems confusing. I tried few different approach, but without success. Do you have some example config with rollup? |
I'll see if I can put something together for you, I haven't looked at sapper in a while but I don't know of a reason why it wouldn't work. |
I think the important bit to note is that svelte does perform CSS optimizations, removing any unused class declarations. Most simple example: <script>
import ChildComponent from './Child.svelte';
</script>
<style>
.class-to-add {
background-color: tomato;
}
</style>
<ChildComponent class="class-to-add" /> ...compiles to CSS without the I'd expect
This looks like a bug / missing feature to me. Not sure how modular-css would help me here. |
Nikku got the point with simpler example. Although modular-css is some solution, I'd rather expect passing hashed classes down as a built in feature. Why? I assume that soon developers will publish more components for svelte, and any possible class conflict is problematic. Yeah, it's rare case, but it is. Also Svelte is so great because developer do not need to worry about class names conflict, except of passing (global) classes to component (sic!). Some React components uses Css-modules to avoid theese conflicts, but in my opinion it's an overkill for simple (and hopefully small) published libs/components. |
This should get addressed via #2888. |
Classes on components are currently conciously not supported. I wonder why is that? |
There's no guaranteed single root element in a component - and the markup in a component should be up to that component anyway, not its parent. |
Could you provide an example / markup to show where that is a problem?
Agreed. And what about if you'd like to customize, lets say the margin of a component, dependent on where it is in the parent? If we look into how customizations in in component frameworks works, passing classes is exactly that. |
I was curious about this too so I've provided a work-around in case you want to try it.
<Anchor hash="#/products" one=true>Products</Anchor>
<Anchor hash="#/services" one=true>Services</Anchor>
<script>
export let hash = "";
export let one = false;
</script>
<-- v---here 'one' is used as a conditional class -->
<a href={hash} class:one={one}>
<slot/>
</a> |
Unfortunately this is not a workaround for the general case of overriding component look and feel provided by UI frameworks. |
@nikku Yeah, it's not ideal. There's another one I just tried. Let's say we are passing in Bootstrap styles.
<Anchor hash="#/products" klass="nav-item nav-link">Products</Anchor>
<Anchor hash="#/services" klass="nav-item nav-link">Services</Anchor>
<script>
export let hash = "";
export let klass = "";
</script>
<a href={hash} class={klass}><slot/></a> |
Using this trick from the docs: https://svelte.dev/docs#script Then |
you can do both, but if you do you also need do :global(.foo) in parent component, because .foo is scoped to parent. This has some constraints, e.g you need to be careful with naming, to avoid clashes. Ideally svelte will provide some mechanism for passing down class (or object of classes) which can be used in child component markup |
That is an easy one too. However, what if you'd like to define your own overrides in your parent component? And pass these to the child component? These will be happily removed aka optimized away by Svelte at the moment. My workaround is to use your second approach + declare the styles defined in the parent component as |
One approach that works is by doing: I would love to be able to create some custom directive like |
Does this prevent classes defined in the parent scope from being optimized away? I believe not. |
@nikku you are completely right.. the approach that I mentioned was working for me as I'm using some global CSS library, but sadly it doesn't work for scoped styles. I believe both things are needed:
|
#2888 does exactly what you mention, in the most lean way. |
@AradAral no petitions, no begging for upvotes. |
@non25 i haven't looked at yr solution yet. i'm sure it's fine, i may even use it in the mean time. however, it's the sort of thing that the framework should implement. the bigger a tool is the more responsibility it has to be a good citizen of its ecosystem (the web, the world, &c) by default. in this case the blessed path, the one most will use, generates pretty illegible and bloated markup, trips up newcomers, deviates from the expected way the web works, &c. imo, that isn't it. |
You don't need it. If a class name is added from the parent to the child component via the
I understood wrong or is this a joke? You do change everything related to a component from its parent(where the component is imported) based on where it's being used. |
hi, today I resolve it with this comment here is my solution: https://gist.github.com/shynome/601c74deeab113b2063eea58ef5d73d8 |
yeesh, still sad about this. perhaps i just don't vibe with or understand svelte's goals. rather than passing classes to components, jumping through hoops to find an idelogically pure solution at the expense of productivity, deviating from common web practices and violating the principle of least surprise, discarding useful prior art like bem and suit, producing unreadable markup, reaching for tight control rather than allowing for leaky abstractions. let the web be free! |
Ok, just finished reading through the 3 years of comments from this issue - quite a lot! Sad to see a lot of people here talking past each other and not really proposing things that wouldn't break the encapsulation model or fully taking into account that a component doesn't necessarily === one element. Really a testament that the convo is still going though and a clear sign the community is active and engaged in solving practical problems. I do see the perspective of both sides but I think having an explicit component interface is probably the more conservative/safer choice so I see why things are the way they are... Personally, I see this ultimately breaking down into two needs:
I'm fairly new to the Svelte ecosystem but that's my perspective.. Is there another need that I'm not seeing? |
@matthewsimo I would need to for repetitive CSS code. |
it's not the framework's job to make that decision, it's providing a piece of general-purpose infrastructure! it can't possibly know about what sort of abstractions are appropriate in my-or-your-or-anyone-else's applications. it reminds me of this post about the "generic repository trap". sure, it's probably better to have a specific contract at the seam, something that maps from enum-valued data to one of a handful of css classes. but if my application's particular use-cases also demand a more generalized abstraction under the hood, that's my business! svelte provides an infrastructural abstraction and is trying to simultaneously enforce application-layer contracts without any knowledge of those applications' particular constraints. everyone in this thread is saying "hey this doesn't suit my application's particular needs" for a reason, the framework doesn't know better. |
I also disagree with this. Yes such an interface is a potential way to introduce code smell if used sloppily, but as @tycobbb said that's not the framework's job to decide. For instance the currently most suggested workaround is using Take something like a I totally agree that there is a lot of talking past each other and finger pointing in these issues, but I think a better solution to that is to focus on the technical issues rather than philosophical ones. The fact this argument is still going after all this time is a testament to how important this feature is for a lot of Svelte's users, and brushing all of that off as "you're trying to use a bad pattern" is unhelpful imo. |
If someone can provide good, specific idioms
without explicitly passing classes or styles exported by the child component, I will follow in your ways and stop asking for a solution to this issue. BTW: What might it look like to add syntactic sugar for components that contain one element? |
If anyone here is using SvelteKit, I've found that Vite's CSS Modules feature has partly solved this problem for me, give it a try. Although it comes with the downside that you have to have a separate |
The way we decided to solve this for the image component case is to use a preprocessor: sveltejs/kit#10788. That solves this styling issue as well as the event handling issue. |
@benmccann image preprocessing looks great, but I think that's a very narrow use-case, in sveltekit only no less, that doesn't solve this broader issue at all |
I'll note that it's not just SvelteKit and any Vite-based project can use it, but I understand there are many additional use cases where you may have similar needs. I wanted to share in case others found the approach useful |
After watching the video about Svelte 5 runes, can we have something like Example:
Not an expert that can actually implement a working prototype, so I will just throw the idea here. |
I'm not sure if this isn't related to other issues, but I checked many of them and neither covers what I need.
I come from React and CSS-Modules, where passing down styles is really easy. Just pass down className prop, and css-modules will figure out and hash styles to avoid conflicts.
In svelte I cannot pass down classes to component through class prop, like so:
https://svelte.dev/repl/1d0b80898137445da24cf565830ce3f7?version=3.4.2
There are some solutions to pass styles, like using
:global
, but it's fragile: if anywhere inside child component will have class named same, it will cause problems. Sure, we can use BEM or another approach, be very careful with global styles, but I imagine it can happen automagically (like with CSS-Modules).Another approach is to add add divs inside componetns, but consider Col component from example above. If we have:
content will get background, but also will have unwanted gap caused by Col padding. And quickly code will have many unwanted divs.
Why I think it matters?
I wrote hundreds of Rect components and what I learned is that Componets should be able to be styled by developer who is using it. Adding BEM layer or sth else is for me unnecessary work. And may cause conflicts. Imagine dev who use BEM. There may be rare cases when his (global) styles are named same as component's and interfere.
in conclusion
It will be great to pass down classes, not be global, but with some unique id.
PS. I found modular-css package, but it's for svelte2, and I'm not sure if it will works with passing down styles to components.
The text was updated successfully, but these errors were encountered: