Customizing how Chakra components use the color scheme - reactjs

Chakra allows you to define and pass color schemes to components, but as far as I've been able to tell, it doesn't allow you to customize how those color schemes are used. For example, the button component will use the 500 shade of whichever color scheme you pass in as its default background and a darker shade for the hover background. Suppose I wanted to invert these though, I'm hoping to do something like...
Button: {
baseStyle: {
bg: colorScheme.700,
_hover: {
bg: colorScheme.500,
},
},
}
Is there any way to define how color schemes are used for a given component? It seems like to override the default shading choices, you have to override all colors explicitly, but hopefully I'm missing something.

You can explore Chakra's source to see how they do this for their components. They're not coded any differently than how you can define your own styles.
We know Buttons utilize the colorScheme prop, so I looked in the code to find out how they apply the prop.
Their core component styles are defined in a base theme and Buttons are no different. The source shows various examples of variants being used, but here's the ghost variant definition:
const variantGhost = defineStyle((props) => {
const { colorScheme: c, theme } = props
if (c === "gray") {
return {
color: mode(`inherit`, `whiteAlpha.900`)(props),
_hover: {
bg: mode(`gray.100`, `whiteAlpha.200`)(props),
},
_active: { bg: mode(`gray.200`, `whiteAlpha.300`)(props) },
}
}
const darkHoverBg = transparentize(`${c}.200`, 0.12)(theme)
const darkActiveBg = transparentize(`${c}.200`, 0.24)(theme)
return {
color: mode(`${c}.600`, `${c}.200`)(props),
bg: "transparent",
_hover: {
bg: mode(`${c}.50`, darkHoverBg)(props),
},
_active: {
bg: mode(`${c}.100`, darkActiveBg)(props),
},
}
})
As you can see, there's something special about this definition (in addition to some helper functions being utilized).
In all of Chakra's examples, they use static objects to override styles. But that's not a necessity. You can use this defineStyle function to return a dynamic object based not only on the current colorMode, but the colorScheme passed to the component! defineStyle can be used on your baseStyle property, as well as your variants and sizes properties too.
You can access defineStyle by importing it from #chakra-ui/react like this:
import { defineStyle } from '#chakra-ui/react'
const theme = extendTheme({
components: {
Button: defineStyleConfig({
baseStyle: defineStyle(props => {
return {
color: `${props.colorScheme}.500`
}
}),
}),
},
})
It's not necessary, but you can get fancier, like in the Chakra source, and use the mode helper function to select different colors for your light and dark mode.

Related

Using theme palette colors in custom MUI component variants with light/dark mode

For readability reasons, I want to split the components object passed in the createTheme function (components may have large variants) and I do have light/dark mode.
According to docs, this is how we get the design tokens:
const getDesignTokens = (mode: PaletteMode) => ({
palette: {
mode,
...(mode === 'light'
? {
// palette values for light mode
primary: amber,
divider: amber[200],
text: {
primary: grey[900],
secondary: grey[800],
},
}
: {
// palette values for dark mode
primary: deepOrange,
divider: deepOrange[700],
background: {
default: deepOrange[900],
paper: deepOrange[900],
},
text: {
primary: '#fff',
secondary: grey[500],
},
}),
},
});
After that, I create the theme depending on whether the mode is light or dark.
The problem is when I'm trying to add a component to the theme (as stated before, each component will be only referenced in the createTheme, the definition would be somewhere else) I cannot use colors from the theme without wrapping the component is a function which has the parameter the mode used.
I wonder if there is any solution like with the sx prop when you're referencing the color as a string, let's say sx={{ backgroundColor: 'button.background' }} and that would automatically be used from the theme.
Wrapping each component in a function with a parameter does the job, but I would like to know if there is any better solution.
How the code is now:
const dashedVariants = (palette) => ({
props: {variant: 'dashed'},
style: {
border: `1px dashed ${palette.dashColor}`
}
})
const Button = (palette) => ({
styleOverrides: {},
variants: [dashedVariants(palette)]
})
vs what I'm trying to acheive:
const dashedVariants = {
props: {variant: 'dashed'},
style: {
border: `1px dashed palette.dashColor` //something like that??
}
}
Note: I've looked over this existing question, but unfortunately this does seem to help.
Due to complexity of CSS properties, many UI toolkit and its themes only parse singular properties(or provide a detour utility); MUI's one of them. Use separate border properties to make parser working. Palette color property parser only works for the type of React.CSSProperties['color'] property. .border property is Property.Border type. The color parser won't work in this case.
Palette type only works with appropriate properties. it does not provide dashColor property. according to MUI doc, working properties are:
.palette.primary.light
.palette.primary.main
.palette.primary.dark
.palette.primary.contrastText
// ...
.palette.secondary
.palette.error
.palette.warning
.palette.info
.palette.success
const theme = {
palette: {
secondary: {
main: '#...' // user defiend color
}
}
}
const dashedVariants = {
props: {variant: 'dashed'},
style: {
borderColor: 'secondary.main',
borderWidth: '1px',
borderStyle: 'dashed',
}
}
There's an experimental CSS variable feature. With this, it is possible to define CSS variable inside complex property. This is probably the closest to the goal but it's currently experimental stage, might be unstable for production use. I am also looking forward to using this in the future.

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

How can I disable some Material UI css for ListItem

I am using the Material-UI ListItem component and I would like to get rid of the default background color. I've already tried using classes but my value gets overwritten by this:
How can I disable this default rule?
You can globally override the style for any Material UI component.
Look for the point in your application where you call createMuiTheme, and add and overrides field like this.
const theme = createMuiTheme({
palette: {
/* you should already have stuff here, keep it */
},
typography: {
/* you should already have stuff here, keep it */
},
overrides: {
MuiListItem: {
root: {
backgroundColor: "red",
},
},
},
});

material-ui defining styles in custom theme

I'm using react with material-ui, and I want to override the theme to match my own needs, I saw that you can change all of the properties of each component, but I tried to change the style of the appbar but nothing happend.
Here is what I tried:
let theme = {
appBar: {
style:{
height: 128
}
}
}
I know I can just change the height of the appbar but lets say I want to change something that is not a property, like the 'top' in the drawer's style, like this:
let theme= {
drawer:{
style:{
top: 64
}
}
}
So how can I do that?
Try setting the values without the style prop.
So instead of:
let theme = {
appBar: {
style:{
height: 128
}
}
}
Change to:
let theme = {
appBar: {
height: 128
}
}
//Example
const muiTheme = getMuiTheme(theme);
...
You can setup only limited range of properties within theme object.
You can discover all supported properties and how they changes the appearance via this online tool.
If you don't have what you need in theme so you may setup it manually via style properties.
Notice, that usually there are some "style" properties in Material-UI components. e.g. style, titleStyle, iconStyleLeft, iconStyleRight for App bar.
Pachu. For answering your question: "how to change the Material-ui's theme?". You can try it:
const muiTheme = getMuiTheme({
palette: {
textColor: cyan500,
},
appBar: {
height: 50,
},
});
You can refer this link: http://www.material-ui.com/#/customization/themes

Resources