-
Notifications
You must be signed in to change notification settings - Fork 383
Description
Describe the feature request
Disclaimer
This proposal is not "ready" or "approved". This proposal is being shared publicly to help consolidate all discussions about adding such a feature.
Motivation
StyleX has a few constraints in service of making things work consistently and generating styles that are performant and scalable. StyleX has disallowed descendent and sibling selectors to maintain it's core principles such as:
- Deterministic styles
- Deterministic merging of styles
- No "styling at a distance"
However, the alternative to such selectors is to use Javascript which may often not be desirable and cause other trade-offs.
Constraints
Any design we adopt for descendent selectors must not compromise on StyleX's core principles.
We must also ensure that such a feature won't significantly affect the performance or size of the generated CSS.
Core Concept
When it comes to avoiding styling at a distance, .csuifyiu:hover > div is unsafe, but div:hover > .ksghfhjsfg is safe.
Inspiration
group and peer from Tailwind.
Proposal
This proposal would add at least two new functions to the StyleX API surface. Although the names could change, for the sake of this explainer, assume they're stylex.id and stylex.when.
The core concept is that stylex.when can be used toe read the state of an element targeted with stylex.id and apply styles conditionally. stylex.when would be allowed to be used where pseudo classes are allowed today.
stylex.id would have the same constraints as stylex.defineVars.
// target.stylex.ts
import * as stylex from '@stylexjs/stylex';
export const myId = stylex.id();import {create, props, when} from '@stylexjs/stylex';
import {myId} from './target.stylex';
const styles = create({
button: {
color: {
default: 'black',
':hover': 'red',
[when.ancestor(myId, ':hover')]: 'blue',
// .a-group:hover .xjygtsyrt
[when.peerBefore(myId, ':hover')]: 'blue',
// .a-group:hover + .xjygtsyrt
[when.peerAfter(myId, ':hover')]: 'blue',
// .xjygtsyrt:has(+ .a-group:hover)
[when.descendent(myId, ':hover')]: 'blue',
// .xjygtsyrt:has( .a-group:hover)
},
}
});
<Card {...props(styles.card, ..., myId)}>
<button {...props(styles.button} />
</Card>Additionally, stylex.id.default should be available as a "default" id that can be used instead of creating ids manually.
Concerns
CSS Bloat
Adding this capability can lead to CSS becoming bloated.
One way to minimise bloat would be disallow creating custom ids and enforce that the same id is used for all use-cases. This would cause the same constraints as group and peer in Tailwind where there can only be a single "layer" of combinator styles at a time. This should be sufficient in the vast majority of use-cases and we can suggest using JS for the edge-cases
API Bloat
This API makes StyleX harder to learn and increases the API surface area.
Naming Bikeshed
The naming of the APIs is up for debate.
Feedback
How important is this feature?
Is the ability to create multiple custom IDs for targeting in styles important?