Closed olivierpascal closed 11 months ago
Did you mean .button:hover::before
?
You wouldn't typically need a pseudo-element here, as you can use an empty element and then set the value of a custom variable (used by the empty element) on :hover
What you are asking for is essentially a descendent selector. We have documented that this is not supported for now.
https://stylexjs.com/docs/learn/thinking-in-stylex/#encapsulation
The current workaround for such situations is to set the value of a variable in the parent and read it in the child.
import {myVars} from './variables.stylex';
const buttonStyles = stylex.create({
shadow: {
[myVars.shadowStart]: {
default: null,
':hover': `0 4px 4px 0 ${colorScheme.shadow}`,
},
},
child: {
boxShadow: myVars.shadowStart,
}
});
That's genius. Thanks.
@nmn Hum after all I think I don't fully get how your workaround works.
How does myVars.shadowStart
is set in your code?
Does [myVars.shadowStart]: { ... }
can really set a var content?
I get eslint: Computed key cannot be resolved
when I am using your syntax.
Also, can stylex.create
be used to set an arbitrary var like --my-var: 'my-content';
? I get eslint: This is not a key that is allowed by stylex
when trying to do so.
Thanks.
Does [myVars.shadowStart]: { ... } can really set a var content?
Yes! StyleX can use variables in both the key and var position. This approach is meant for one-offs, as opposed to createTheme
which is meant to override a bunch of variables together.
I get eslint: Computed key cannot be resolved when I am using your syntax.
This is bug in the ESLint plugin. I tried to fix it just before release, but it needs some more work.
...can stylex.create be used to set an arbitrary var like --my-var: 'my-content';?
This is not an officially supported pattern because you're using a non-StyleX variable, but it does work.
Ok thanks. After all it seems very hacky to me, and too complicated for my usecase. I end up using JS events onPointerEnter
/ onPointerLeave
and a React state variable. Still hacky, not perfect but cleaner imho, waiting for a formal API for descendants and siblings.
We know the approach we can take, but still discussing the API. Will share an RFC soon.
What you are asking for is essentially a descendent selector. We have documented that this is not supported for now.
Will you also support 'ascendent' selectors?
The current workaround for such situations is to set the value of a variable in the parent and read it in the child.
Do you by any chance have a workaround to address this?
<!-- the div container has to be red when the button is hover -->
<div class="container">
<button>Button</Button>
</div>
.container:has(button:hover) {
background-color: red;
}
Here is my workaround:
const styles = stylex.create({
container: {
backgroundColor: {
default: 'inherit',
':has(button:hover)': 'red',
},
}
});
NOTE: as @nmn mentioned, "this is a workaround and may stop working sometime in the future.".
@olivierpascal That workaround is fine and doesn't break encapsulation. (There is no styling at a distance, only observing). The official API will generate the same thing eventually. So yes, we're looking at selectors in all 4 directions.
It is unlikely, however, that any of these selector types will be supported in React Native - especially when it requires knowledge of the underlying element type that might be encapsulated within a composite component
Yes, to be clear, no complex selectors will be supported in React Native at all. In any of the four directions.
Arguably anything like this - :has(button:hover)
- shouldn't be allowed on web either, as part of the selector is an element type - and there could be many or no button
elements in the subtree. Inevitably people will want to scope this to a specific button when it goes bad, and will probably reach for a more specific selector type like an attribute selector. Not to mention that :hover
-related styling has general drawbacks for touch device UX. Ignoring my skepticism about this pattern being a good UX, the most reliable mechanism is probably to use JS callbacks.
Is there a workaround for sibling selector such: .mycheckbox:checked + .label span
In a case such:
<input
type="checkbox"
/>
<label>
<span>content</span>
</label>
I'd like to change the span property based on the 'checked' state of the input.
thanks.
Using the "checkbox hack` is considered bad for accessibility anyway.
I'd suggest using JS to do this and also set the correct aria-attributes accordingly.
What you are asking for is essentially a descendent selector. We have documented that this is not supported for now.
stylexjs.com/docs/learn/thinking-in-stylex#encapsulation
The current workaround for such situations is to set the value of a variable in the parent and read it in the child.
I'm currently trying to style an input[type=range]
and I think I'm facing a similar problem. Consider this code that styles the slider's thumb based on the hover of the input:
.slider {
&::-webkit-slider-thumb {
background-color: red;
}
&:hover::-webkit-slider-thumb {
background-color: green;
}
}
If I understand the variable use correctly, this would be the workaround:
const someVars stylex.defineVars({
thumbHover: "unset",
});
const slider = stylex.create({
slider: {
[someVars.thumbHover]: {
default: "red",
":hover": "green",
},
"::-webkit-slider-thumb": {
backgroundColor: someVars.thumbHover
},
},
});
Is this approach correct? If so, does it resemble the current best practice?
ESlint currently yields: Keys must be strings
via eslint(@stylexjs/valid-styles)
To align my mental model of what this does internally, does the resulting code end up in something like this (the var name being generated in some way by the compiler)?
.slider {
--someVars-thumbHover: red;
&:hover {
--someVars-thumbHover: green;
}
&::-webkit-slider-thumb {
background-color: var(--someVars-thumbHover);
}
}
@nikeee Yes, this is currently the recommended best practice.
The one important thing to note is that you must follow the rules when defining variables when using stylex.defineVars
. i.e., stylex.defineVars
must be in a separate file and the file name must have a .stylex.ts
extension.
Making this change will also fix the lint error that you're seein.
// tokens.stylex.ts
export const someVars stylex.defineVars({
thumbHover: "unset",
});
// somefile.tsx
import {someVars} from './tokens.stylex.ts';
const slider = stylex.create({
slider: {
[someVars.thumbHover]: {
default: "red",
":hover": "green",
},
"::-webkit-slider-thumb": {
backgroundColor: someVars.thumbHover
},
},
});
Is your feature request related to a problem? Please describe.
I would like to target
.class[pseudo class] [pseudo element]
, ie..button:hover ::before
.Describe a solution you'd like
Describe alternatives you've considered
I have no alternative yet.