My use case is as follows: I need to make a form label 'visually hidden' on some screens, and visible on others. For accessibility this cannot be a simple display: none and it needs to apply a several styles.
Using custom style declarations, this might be possible, although it would not be neat as it would require binding a bunch of different properties to the same prop.
Using custom variant keys there doesn't seem to be a way to access breakpoints.
Is there some combination of the two that would work? Ideally it would look something like:
<Label visuallyHidden={[true, false, false]}>My form label</Label>
Currently there isn't a notion of a responsive variant – this seems like a fairly small use-case, and I'd recommend adding your own prop to handle this sort of thing
I am also trying to do something like a responsive variant. Without any kind of responsiveness, I can't find too much use for variants on their own (though I may be missing something).
It would be great if I could do something like:
const headings = variant({ key: "headings" });
export const Heading = styled(Text)(themed("Heading"), headings);
And inside of the theme object:
headings: {
small: {
fontSize: ["1em", "1.25em", "1.5em" ]
},
big: {
fontSize: ["2em", "2.5em", "3em" ]
}
}
Based on your response here, and to some other similar issues don't see this happening (and it may not make sense, or just not be very viable), but how do you recommend we do something like this cleanly?
Right now I just use a function component, and literally pull the values from a map, but this is pretty messy imo.
I got something that works for our use case, but discovered a few things that made me realise this was a bad candidate for a feature that could be merged.
It is really hard to negate a css block. In my example above, when you add false in doesn't add the css to the selected media query, but that doesn't mean that the css won't be inherited from the previous media query due to:
styled-system only uses min-width in it's media queries (which is smart and avoids a lot of problems). But for our solution to work, we need to have a media query with a min-width and a max-width.
This sounds different to what is proposed @Jrayp but that might run into similar complications.
@Jrayp my suggestion for your example is to use props (e.g. map props) and avoid mixing props objects with the theme & style objects
@Jrayp my suggestion for your example is to use props (e.g. map props) and avoid mixing props objects with the theme & style objects
@jxnblk Do you have any examples that show clear delineation of theme, style, and props objects in context? Why one would use one and not the other in typical use cases? I am looking at https://jxnblk.com/styled-system/ and trying to find something akin to (A) https://tachyons.io/components/ (usage in isolation/vaccum) and (B) https://tachyons.io/gallery/ (usage in context/actual environment) where I'm struggling to find some B's. Perhaps I am missing a good link/reference... Please advise!
I figured out a "_responsive variant_" for my project. My solution is based on some utils which are already exist in styled-system package:
import {
get,
defaultBreakpoints,
createMediaQuery,
variant,
cloneFunc,
propTypes
} from "styled-system";
const variantResponsive = variantProps => {
const { prop = "variant", key } = variantProps;
const defaultVariant = variant(variantProps);
const fn = props => {
const { [prop]: variantProp } = props;
if (!Array.isArray(variantProp)) {
return defaultVariant;
}
const breakpoints = [
null,
...(get(props.theme, "breakpoints") || defaultBreakpoints).map(
createMediaQuery
)
];
let styles = {};
for (let i = 0; i < variantProp.length; i++) {
const media = breakpoints[i];
const mediaVariant = {
...defaultVariant({ ...props, [prop]: variantProp[i] })
};
if (!media) {
styles = mediaVariant || {};
continue;
}
const rule = mediaVariant;
if (!rule) continue;
styles[media] = rule;
}
return styles;
};
fn.propTypes = { [prop]: cloneFunc(propTypes.responsive) };
fn.propTypes[prop].meta = {
prop: prop,
themeKey: key,
styleType: "responsive"
};
return fn;
};
export default variantResponsive;
Usage:
// define theme
const theme = {
buttons: {
normal: {
color: "black",
backgroundColor: "white"
},
inverse: {
color: "white",
backgroundColor: "black"
}
}
};
// define responsive variant
const buttonStyle = variantResponsive({
key: "buttons"
});
// define styled button
const Button = styled.button`
${buttonStyle};
`;
// responsive usage
function App() {
return (
<ThemeProvider theme={theme}>
<Button variant={["inverse", "normal"]}>Button text</Button>
</ThemeProvider>
);
}
Codesandbox example:
Maybe that will be useful for someone.
p.s. I'm not sure that I've done it right.
There is a built-in buttonStyle function, so you shouldn't need to define your own
@jxnblk built-in buttonStyle isn't responsive, is it?
Oh, sorry I mixed this issue up with a different one, carry on
Hi, I am having the same requirements as @Jrayp, in the design I am trying to implement. There are a limited set of text styles from the designer, but all text styles, changes in size when going from mobile to desktop.
The same is going on with buttons and other elements. Eg. the "primary" variant of a button, adds more padding when going from mobile to desktop.
Generally I think some of this is outside of the scope that variant was intended to handle, so I'm going to close this issue out.
As another suggestion for how to handle responsive variants, media queries can be used in the theme's style objects for variants, for when you want things to change responsively across the board
Currently there isn't a notion of a responsive variant – this seems like a fairly small use-case, and I'd recommend adding your own prop to handle this sort of thing
The Design systems that I've been subjected to recently have typically defined different style rules at varying breakpoints for elements such as <p>, <h1> and so on. Not having a utility to define this in a theme reduces its re-usability across projects considerably.
I'm not saying whether this is right or wrong for DS' to define this, however not being able to do it in the theme makes me sad.
@Daveawb Sorry, I don't mean to make you sad :/ I'm not opposed to making the variant utility work in some responsive way, but the general convention in Styled System is that responsiveness is a concern of the component, not the theme. That said, I think this WIP PR is a good indication of intent to make variants more powerful, FWIW #583
@jxnblk Aww I didn't mean it like that, just a throw away comment. I'm actually seeing this now in many many many design systems. I'm still unsure whether it's an anti pattern for DS' where designers and UX teams alike still don't really understand the value of it or there are valid design concerns that need conveying via a DS. I suspect it's a bit of both, either way thanks for the link, this made a massive difference.
@Daveawb since this issue is pretty old and for clarity, variants now support responsive values, e.g.:
variant({
variants: {
big: {
fontSize: [ 3, 4, 5 ],
},
small: {
fontSize: [ 1, 2, 3 ],
}
}
})
@jxnblk, is something like the following possible, or would it be possible to add the functionality? Similar to what we are able to do with components. https://styled-system.com/responsive-styles#using-objects
variant({
variants: {
big: {
fontSize: {
_: 3,
md: 4,
xl: 5
},
},
small: {
fontSize: {
_: 1,
md: 2,
xl: 3
},
}
}
})
@jxnblk, is something like the following possible, or would it be possible to add the functionality? Similar to what we are able to do with components. https://styled-system.com/responsive-styles#using-objects
variant({ variants: { big: { fontSize: { _: 3, md: 4, xl: 5 }, }, small: { fontSize: { _: 1, md: 2, xl: 3 }, } } })
I'm trying to wrap my head around all the tools in this ecosystem, and also found this to be some sort of asymmetry? The css package doesn't support objects for breakpoints. Is it intentional?
Most helpful comment
I figured out a "_responsive variant_" for my project. My solution is based on some utils which are already exist in styled-system package:
Usage:
Codesandbox example:
Maybe that will be useful for someone.
p.s. I'm not sure that I've done it right.