xstyled
xstyled copied to clipboard
Variant alternative
I'm considering migrating from styled-system to xstyled. So far migration seems simple expect variants which I found were removed in v2. What is recommended way to handle variants, for example different types of button (e.g. icon, solid, dashed).
For now you can do it by yourself, personally I use a data-variant
:
import styled from '@xstyled/styled-components'
const InnerButton = styled.buttonBox`
&[data-variant="success"] {
background-color: emerald-300;
color: emerald-600;
}
`
const Button = ({ variant, ...props }) => <InnerButton data-variant={variant} {...props} />
You can also do it directly with x.button
.
import { x } from '@xstyled/styled-components'
const variantProps = {
success: {
backgroundColor: 'emerald-300',
color: 'emerald-600',
}
}
const Button = ({ variant, ...props }) => {
return <x.button {...variantProps[variant]} {...props} />
}
Pick the best for you but a utility is not helpful :)
I will add a section in docs about that.
For now there's no variant
way in xstyled but it will be the next focus.
@gregberge I'm curious what you're thinking here. I've been using something based on your data-variant
idea:
const hoistDataAttrs = mapping => {
const [oks, nks] = Array.isArray(mapping) ?
[Object.keys(mapping), Object.values(mapping)] :
[mapping, mapping.map(k => `data-${k}`)]
return props => {
const vs = oks.map(k => props[k]).map(v => v === true ? '' : v)
return Object.fromEntries([
// Map variant to data-variant, dropping false and null.
...oks.map((ok, i) => [nks[i], vs[ok]])
.filter(([_, v]) => v !== false && v !== null),
// Map old keys to undefined so they'll be dropped by styled-components.
...oks.map(ok => [ok, undefined]),
])
}
}
const Button = styled.button.attrs(hoistDataAttrs(['variant']))`
&[data-variant="success"] {
...
}
`
I've been thinking about applying this globally for my own projects, but I haven't tried it yet:
const hoistVariants = hoistDataAttrs(['size', 'variant'])
Object.entries(styled).forEach(([k, v]) => {
styled[k] = v.attrs(hoistVariants)
})
but maybe you have a new idea?
@gregberge I'm curious what you're thinking here. I've been using something based on your
data-variant
idea:
Hello, I have never industrialized it yet.
Hello, i was looking for 'variants' and i found this issue. Just showing here what I tried before:
// theme.js
import {
defaultTheme
} from '@xstyled/styled-components'
export const theme = {
...defaultTheme,
variants: {
bPrimary: {
backgroundColor: "#aaa"
}
}
}
// xstyled.config.js
import {
createCss,
system,
compose,
style,
themeGetter,
} from "@xstyled/styled-components";
const getVariants = themeGetter({
name: "variant",
key: 'variants',
transform: (value) => {
return value
},
});
export const variant = style({
prop: "variant",
css: (value) => {
return value;
},
themeGet: getVariants,
});
export const { css, styled, x, createGlobalStyle } = createCss(
compose(system, variant)
);
Usage example:
<x.button variant="bPrimary">Button</x.button>
This code allow a 'variant' property in all x.* elements, but not worked as expected. It works only with default css values. Example: this code can not transform "backgroundColor: blue-700" in "backgroundColor: #1d4ed8".
I don't know if it's a good code but I leave this code here as an implementation idea.
One thing I'd love to see when variants are implemented is the ability to switch the applied variant based on media query. For example, perhaps a Button on mobile would look like a link and on desktop would look like a button (essentially reducing the surface area of how many styles have to be manually wired up with media queries individually.)