Dynamic values in material ui's makeStyles - reactjs

I have some styles stored in a database so users can restyle their components - along the lines of:
const stylesFromDatabase = {
backgroundColor: "blue",
color: "red"
}
Is it possible to bring these styles into material UI's makeStyles - perhaps something like this?- edited -
const useStyles = makeStyles(theme => ({
textField: stylesFromDatabase => ({
width: "100%",
...stylesFromDatabase
}),
Alternatively, is there anything I can use to smoosh together the classes generated by makeStyles and a javascript object?

Yes, It's absolutely possible to include a JavaScript object into makeStyles.Thanks to the spread operator.
Advice is to spread over the object first, so that you can easily override any styles.
Therefore it's preferred to do as follows.
const useStyles = makeStyles(theme => ({
textField: {
...stylesFromDatabase, // object
width: "100%",
color: "green", // this would override "red" (easier fine tuning)
},
});

For the benefit of future posters, the code in my original post worked perfectly, I just had something overriding it later! (Without the callback function it was undefined) – H Capello just

Related

fluent ui styling, border is not defined

i am using fluent ui which uses Griffel for styling. When i try to provide border: "none" it's throwing error that string not assignable to undefined
import {makeStyles} from "#fluentui/react-components";
export const settingsButtonStyle = makeStyles({
root: {
border: "none",
background: "#E5E5E5",
marginRight: "13px"
},
rootHovered: {
background: "#E5E5E5",
}
});
GriffelJS tries to make Atomic CSS classes, so they don't support CSS shorthands (like border or background) right away. But there is a helper function called shorthands to manage some of theses. Background is not included in the helper function, so there you should use the specific CSS proprety. So your code should look like this:
const useStyles = makeStyles({
root: {
...shorthands.border("0"),
// or
...shorthands.borderStyle("none"),
backgroundColor: "#E5E5E5",
marginRight: "13px"
},
})
You find more infos to shorthands in GriffelJS in their documentation shorthands - GriffelJS

MUI v5: How to generate style classes for interop with other libraries?

I am using MUI v5 together with Quill in React.
I can pass a className prop to the ReactQuill component and change it's styling:
const useStyles = makeStyles((theme) => ({
editor: {
'& .ql-editor': {
border: 'none',
// and so on...
}
}
}))
<ReactQuill className={classes.editor} ... />
Now with MUIv5 and its migration to emotion, this is not possible anymore. My workaround currently is to wrap the ReactQuill element inside a div like so:
const ReactQuillContainer = styled('div')(({theme}) => ({
'& .ql-editor': {
border: 'none',
// and so on...
}
}))
<ReactQuillContainer>
<ReactQuill ... />
</ReactQuillContainer>
But this changes the underlying DOM structure.
Is there a way to achieve the old result in the new way? I know about the css function, however I need the theme for styling and I don't think that is possible.
I also don't want to inline all those styles.
Have you solved this yet? I'm facing a similar issue, where I'd like to programmatically set MUI TextField styling on a Quill editor.
If not, have you tried passing Quill itself to styled? This works for me, though it doesn't solve my core problem. I'm also not sure it will allow you to set styles on child classes, but that may not be an issue.
const StyledQuill = styled(ReactQuill)(({ theme }) => ({
color: theme.palette.warning.main,
// and so on...
}));

MUI - Slow makeStyles if using props in methods

I have an issue where I render lots of components, where each of these components have a useStyles. We want the components props to affect the styling, so we combine props and theme settings. Works fine, except that it's incredible slow and I have narrowed it down to it being caused by having prop methods in makeStyles.
It actually doesn't matter if the class is used or not. If all classes are static it's fast, but if I add an unused class that is a method it's slow. The prop doesn't matter either, like if I add test: { fontWeight: () => 'bold' } it's going to be slow again.
Very weird indeed. I'm using Material UI ^4.11.0. Not the latest version of v4. Bug? Anyone heard of this? Anyone got a better solution for adding prop based styles and using the theme at the same time? Anyone got a performance improvement by using useMemo or anything? (It had not effect when I tried).
const useStyles = makeStyles(({ typography }) => ({
fontFamily: {
fontFamily: ({ fontFamily }: any) => fontFamily,
},
fontFamilySecondary: {
fontFamily: typography.fontFamilySecondary,
},
...filterCustomVariants(typography),
bold: {
fontWeight: typography.fontWeightBold,
},
boldScondary: {
fontWeight: typography.fontWeightBoldSecondary,
},
italic: {
fontStyle: "italic",
},
thisIsNotEvenUsed: {
fontWeight: () => {
console.log("Running running running") // Runs many times anyway!
return "bold"
},
},
}))
And the implementation:
const styleProps = { fontFamily: fontFamily }
const classes = useStyles(styleProps)
EDIT: Here are a CodeSandbox that shows this behavour, using latest MUI v4 and without my Apps complexity: https://codesandbox.io/s/black-monad-tr05l?file=/src/App.tsx
This is not a bug, makeStyles in v5 behaves the same way. The dynamic styles using callback is a JSS feature. But JSS dynamic performance has been known to be pretty terrible (see the performance section for more detail, it's about 6 times slower than emotion). That's one of the reason the MUI team decided to abandon it in favor of emotion in v5 which uses dynamic styles heavily.
And yes, it always invokes the callback even if you don't pass anything inside and don't make use of the classes object. It traverses the style object and invoke every callbacks it found when you call useStyles. For more detail about how makeStyles works, I recommend you reading this answer from Ryan.
const useStyles = makeStyles({
thisIsNotEvenUsed: {
fontWeight: () => {
console.log("Running running running"); // Runs many times anyway!
return "bold";
}
}
});
const unusedClasses = useStyles(); // generate the styles
There are some strategies to improve the performance. The easiest one (depend on the situation) is to upgrade to v5 to leverage emotion and its capability to generate dynamic styles efficiently. Another approach is to use the inline styles:
<Typography style={{ fontWeight: props.fontWeight }}>
But if you don't want to pollute your component with inline styles, you can still use makeStyles using the 'style injection' method by creating a nested styles in the container that holds a large amount of elements inside (Grid, List, Stack...)
const useStyles = makeStyles({
root: {
"& MuiTypography-root": {
fontWeight: () => 'bold'
}
}
});
<div className={classes.root}>
{[...Array(100)].map((_, index) => {
return <Text key={`text_${index}`}>Text Component</Text>;
})}
</div>

How can I consistently overwrite JSS styles which have indeterminate suffixes?

I’m looking for advice around #material-ui/core in react,
TLDR;
I would appreciate a consistent approach for handling CSS-in-js generated classNames which have indeterminate numeric suffixes, while still using #material-ui/core's styled() function if possible.
Specifically
“the class names generated by #material-ui/core/styles are non-deterministic” (https://material-ui.com/styles/advanced/#class-names), but so far at my company the projects I’ve been on have used the styled() function for wrapping components to apply styles.
It works great, until I want to overwrite how one of the pseudo-classes applies to the root element that I’m styling. At which point, if I try to use a regular old class-selector to take control of the styling in ta specific state, it’ll work if there’s no suffix on the class, but as soon as the JSS generated className has a numeric suffix, it breaks.
When I say "suffix" I'm referring to how a component's root className might be .makeStyles-root but when the className is generated for that specific instance, it likely has a numeric suffix appended: .makeStyles-root-123
For example:
Component: InputLabel https://material-ui.com/api/input-label/#inputlabel-api
I want to fiddle with the transform that happens, which comes from .MuiInputLabel-formControl, but then that transform is overwritten by .MuiInputLabel-shrink.
If I try using a regular class selector:
export const InputLabel = styled(MuiInputLabel)({
`&.MuiInputLabel-formControl`: {
transform: 'translate(2px, 8px) scale(1)',
},
`&.MuiInputLabel-shrink`: {
transform: 'translate(0) scale(0.6)',
},
});
It works only if the JSS class doesn’t have a suffix,
and if I try using the rule names (I don’t think it’s actually supported with styled())
export const InputLabel = styled(MuiInputLabel)({
formControl: {
transform: 'translate(2px, 8px) scale(1)',
},
shrink: {
transform: 'translate(0) scale(0.6)',
},
});
It just applies invalid rules to the element:
formControl: [object Object]
shrink: [object Object];
I've also tried passing classes (but that didn't seem to work at all)
export const InputLabel = styled((props) => (
<MuiInputLabel
classes={{
formControl: {
transform: 'translate(2px, 8px) scale(1)',
},
shrink: {
transform: 'translate(0) scale(0.6)',
},
}}
{...props}
/>
))({});
Further Notes
I don’t want to use a theme override (which I imagine would enable the use of those rules here) because I don’t want this styling to apply to all instances of a InputLabel
so that leaves me leaning towards using the hook api / makeStyles() : https://material-ui.com/styles/basics/#hook-api
But that doesn’t lend itself well to current patterns with style files.
Related
I've seen these similar questions:
jss to override a material-ui nondeterministic class
How override material ui style with hooks
the difference is that I'm trying to avoid using the hook api if possible.
As far as I can tell, it isn't possible to do this with styled(),
so I've just gone with what other posts have suggested and used makeStyles().
However I have used a bit of a mash-up of the two, so that I can still keep my styling in a separate file.
const useLabelStyles = makeStyles((theme) => ({
root: {
color: theme.text.primary,
},
formControl: {
transform: 'translate(2px, 8px) scale(1)',
},
shrink: {
transform: 'translate(0) scale(0.6)',
},
}));
export const InputLabel = styled((props) => {
const theme = useTheme();
const classes = useLabelStyles(theme);
return (
<MuiInputLabel
classes={classes}
{...props}
/>
);
})({});

Apply radiobutton color using styled-components in Material UI?

In the Material UI documents, they provided sample code to show how one can change the color of a Radiobutton.
const GreenRadio = withStyles({
root: {
color: green[400],
'&$checked': {
color: green[600],
},
},
checked: {},
})(props => <Radio color="default" {...props} />);
I would like to replicate this with styled-component instead i.e. const StyledRadio = styled(Radio) but I am not too familiar with the syntax such as the ampersand and the dollar sign - how can I do this?
When using styled components with MUI, the CSS is applied to the root class of the component. If you need to apply a more specific style, then you'll need to target the relevant class. In this case, you'll need to target the .Mui-checked class:
const StyledRadio = styled(Radio)`
color: ${green[400]};
&.Mui-checked {
color: ${green[600]};
}
`;
The MUI docs are really good in that they list the CSS classnames for each component. If you visit the API docs for the Radio component, you'll see the .Mui-checked class listed there (under the 'Global Styles' column).
Here's a working example in Code Sandbox: https://codesandbox.io/embed/styled-components-9pewl
Here's the appropriate styled-components syntax:
const GreenRadio = styled(Radio)`
color: ${green[400]};
&.Mui-checked {
color: ${green[600]};
}
`;
Related documentation: https://material-ui.com/customization/components/#pseudo-classes

Resources