component scoped private props

I’ve seen KPow do this in several videos with the locally scoped custom prop whose value is set to a global prop but then in the modifier class, changes the global prop. Haven’t really grasped why he changes the global one (sans underscore) instead of the local one (with underscore). Or vice versa just abstain from making a local and just use the global. I’m sure there’s a good reason but why ? Wouldn’t you want to change the locally scoped :nth-of-type(2){ —_border: hotpink ; }
That has the indicator (the underscore) that it’s a private prop if you’re going to declare it anyway? Is it just to ensure a fallback? People coming upon the modifier class (.bubble-1) will see —border and go looking in the root for it?
No description
14 Replies
MarkBoots
MarkBoots2mo ago
Its just to differentiate the vars. When you see a var with an underscore, you'll know it is set in the component your working on. So you dont have to look all the way up for the global vars Also its is easier if you want to override a value for a specific scenario without changing the default
clevermissfox
clevermissfox2mo ago
I understand that the underscore denotes a private property that’s locally scoped. But why bother setting it to another property , without an underscore and needing a fallback . When I see .bubble-one { —border: pink} I’m looking up in the root for —border. The convention I always used was to use the underscore to denote locally scoped custom props. Sans underscore means it’s global. If it’s not and you have to give it a fallback anyway… this is how I usually handle it.
.class {
—_border: pink;
border: var(—_border)
}
.class.mod { —_border: lime; }
.class {
—_border: pink;
border: var(—_border)
}
.class.mod { —_border: lime; }
Otherwise with .class.mod { —border: lime} I’m looking up in the root for the original value which seems to defeat the locally scoped private property purpose. Sorry I’ve been up all night and I don’t think I’m being clear. Why go to trouble of setting the locally scoped prop with the underscore if you are just gonna change —border in the modifier class, sans underscore and no indication that it’s locally scoped. Why wouldn’t you change —_border in the modifier class instead ? I just don’t see the benefit of it but I’m sure there is one so struggling to understand
MarkBoots
MarkBoots2mo ago
yea, in this case I won't bother as well, but I can imagine it being a bit more useful with a larger codebase and more props/values shared over multiple different components
clevermissfox
clevermissfox2mo ago
Thanks for reading that mess 🤦🏻‍♀️ I’ve been up all night coding for 4 nights in a row and not getting enough catch-up sleep in bw. yeah maybe to ensure there is a fallback from a global prop or something.
Kevin Powell
Kevin Powell3w ago
the idea is from this post by Lea Verou: https://lea.verou.me/blog/2021/10/custom-properties-with-defaults/ She does a good job breaking it down there, including the callbacks, I think, but if you want me to break it down more I can make an example tomorrow 😊
clevermissfox
clevermissfox3w ago
I did read this, and my main question was: Why bother setting a locally scoped custom property e.g. --_clr: var(--color) , if in the modifiers you change the global one anyway
.card { --_clr: var(--color); color: var(--_clr); }
.card.modifier-1 { --color: purple;}
.card.modifier-2 {--color: pink}
.card { --_clr: var(--color); color: var(--_clr); }
.card.modifier-1 { --color: purple;}
.card.modifier-2 {--color: pink}
Why not change --_clr ? I looked into it a lot and asked around and the conclusion I came to was fallbacks. Still feel like I'm missing something though...
Kevin Powell
Kevin Powell3w ago
First, I generally don't use them like Lea proposed, even though I think it's a good system. I normally just got with the --_ means it's local, and that's it. But hers opens up a few extra doors, and the big benefit is the fallbacks, like people say... but most people don't explain why that's a good thing 😅. I made that mistake in the video I made on them as well. I'll include an example at the end that shows why having a fallback is a better option though 😄 So, for a card, you might do this, where --card-color isn't a global variable, it's simply never defined anywhere, so it uses the fallback as a default.
.card {
--_card-color: var(--card-color, black);
--_card-surface: var(--card-surface, white);

color: var(--_card-color);
background-color: var(--_card-surface);
}
.card {
--_card-color: var(--card-color, black);
--_card-surface: var(--card-surface, white);

color: var(--_card-color);
background-color: var(--_card-surface);
}
So, my default card has black text and a white background. Then, we could make modifiers:
.card.inverse {
--card-color: white;
--card-surface: black;
}
.card.inverse {
--card-color: white;
--card-surface: black;
}
Again, with how Lea proposed it, we don't overwrite the original custom property, we supply that custom property with a value that it can use other than it's fallback. And then there is the actual big benefit that most people miss. Let's say I did this:
<section class="card-group bright">
<div class="card"> ... </div>
<div class="card"> ... </div>
<div class="card"> ... </div>
</section>
<section class="card-group bright">
<div class="card"> ... </div>
<div class="card"> ... </div>
<div class="card"> ... </div>
</section>
.card-group.bright {
--card-color: red;
--card-surface: yellow;
}
.card-group.bright {
--card-color: red;
--card-surface: yellow;
}
With that above code, the cards would get that styling. If we did this instead:
.card {
--_card-color: black;
--_card-surface: white;
}
.card {
--_card-color: black;
--_card-surface: white;
}
Because there are no fallbacks, and because of how custom properties work with the cascade, the default black and white would apply, not the styles coming in from the parent like I wanted.
clevermissfox
clevermissfox3w ago
Oookkayyy that’s definitely making more sense. I was thinking var( —card-color) WAS a global property . I can def see the benefit of being able to use on the parent, card-group. Really appreciate you taking the time to explain it as it was driving me crazy that I couldn’t understand the WHY of it all 🤣
Kevin Powell
Kevin Powell3w ago
It took me a while to wrap my head around it as well, and it still takes me a minute to remember that last part 😅
clevermissfox
clevermissfox3w ago
Why arent my fallbacks working here? ps. this was originally in an icodethis editor without @layers and gave me the same behaviour so thats not a factor https://codepen.io/Miss-Fox/pen/gOJembG?editors=1100 i intentionally set to either vars that dont have a value or vars that dont exist/have never been declared to check the fallback
Kevin Powell
Kevin Powell3w ago
The custom properties your assigning to them are black 😊
css
/* COLORS + BG-COLORS */
--clr-primary: ;
--clr-accent: ;
--clr-accent-alpha: ;
--clr-neutral-100: oklch(100% 0 303);
--clr-neutral-900: oklch(0% 0 303);

--clr-bg-body: ;
--clr-bg-card: ;
css
/* COLORS + BG-COLORS */
--clr-primary: ;
--clr-accent: ;
--clr-accent-alpha: ;
--clr-neutral-100: oklch(100% 0 303);
--clr-neutral-900: oklch(0% 0 303);

--clr-bg-body: ;
--clr-bg-card: ;
clevermissfox
clevermissfox3w ago
but shouldnt the fallback still work?
i intentionally set to either vars that dont have a value or vars that dont exist/have never been declared
okay, i am seeing the difference between using --_btn-bg or --btn-bg in the modifier :is(.btn-primary) {--btn-bg: var(--doesnt-exist) } if i change the values to something thats never been declared then the fallback is applied . but if i apply :is(.btn-primary) {--_btn-bg: var(--doesnt-exist) } there is no fallback. finally getting what everyone is talking about with the fallback.
Kevin Powell
Kevin Powell3w ago
A space is a valid value for a custom property. Its used for a neat hack actually https://lea.verou.me/blog/2020/10/the-var-space-hack-to-toggle-multiple-values-with-one-custom-property/
clevermissfox
clevermissfox3w ago
very interesting thank you for that link! i can def see it coming in handy to have a whitespace variable for hacky things