Define Multiple Styles React - reactjs

Is it possible to define multiples classes in React just like in CSS?
const useStyles = makeStyles((theme) => ({
header1,
header2,
header3,
header4: {
display: 'flex',
justifyContent: 'center',
},
}));

I'm afraid #material-ui/styles library usage does not work that way. Each key in the object you define represents one class name.
So trying to do something like this:
const useStyles = makeStyles((theme) => ({
'header1, header2, header3, header4': {
display: 'flex',
justifyContent: 'center'
},
}));
Will result in unusable or invalid class names when the code gets compiled to CSS, because the library will try to compile 'header1, header2, header3, header4' into one class, and since the name contains a space character, the result is garbage.
To solve your problem, the closest thing I can come up with is to define the styles object as its own constant, then assign it to the needed keys. You can also override the original object using spread syntax. Something like:
const headerStyles = {
display: 'flex',
justifyContent: 'center'
};
const useStyles = makeStyles((theme) => ({
header1: headerStyles,
header2: headerStyles,
header3: headerStyles,
header4: {
...headerStyles,
color: 'red'
}
}));
I hope this is a close-enough compromise for you.

You're currently defining an object in the makeStyles method. this ain't CSS.
If you prefer CSS syntax over JSS, you can use the jss-plugin-template plugin.
And write something like this:
const useStyles = makeStyles({
root: `
.header1,
.header2,
.header3,
.header4 {
display: flex;
justifyContent: center;
}
`
});
Reference: https://material-ui.com/styles/advanced/#string-templates

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

how to use vanilla-extract for `style` attribute?

Have a following sample of code which I want migrate to vanilla-extract, my main question is how to generate styles for style attribute in this case?
// in ColorToken.tsx
function ColorToken(props: { name: string; value?: string }) {
return (
<div
style={{
backgroundColor: `var(${props.value})`,
border: 'solid 1px var(--color-border-neutral)',
borderRadius: '100%',
width: '70px',
height: '70px',
}}
>
{props.name}
</div>
);
}
I tried two approaches:
First
// ColorToken.css.ts
import { style } from '#vanilla-extract/css';
export function colorSelector(bgColor: string) {
return style({
backgroundColor: bgColor,
border: 'solid 1px var(--color-border-neutral)',
borderRadius: '100%',
width: '70px',
height: '70px',
});
}
// ColorToken.tsx
import * as selectors from './Colors.css';
function ColorToken(props: { name: string; value?: string }) {
const color: string = // dynamically piking color based on props.
return (
<div className={selectors.colorSelector(color)}>
Error / issue:
error - ./pages/styles/tokens/Colors.css.ts
Error: Invalid exports.
You can only export plain objects, arrays, strings, numbers and null/undefined.
at Array.map (<anonymous>)
Second
// ColorToken.css.ts
export const colorSelector = {
border: 'solid 1px var(--color-border-neutral)',
borderRadius: '100%',
width: '70px',
height: '70px',
};
// ColorToken.tsx
import { style } from '#vanilla-extract/css';
import * as selectors from './Colors.css';
function ColorToken(props: { name: string; value?: string }) {
const color: string = // dynamically piking color based on props.
return (
<div className={style({ ...selectors.colorSelector, backgroundColor: color })}>
Note: here I'm using style function because I think VE might apply some extra things (e.g add vendor prefixes, optimizations etc).
Error / issue:
Unhandled Runtime Error
Error: Styles were unable to be assigned to a file. This is generally caused by one of the following:
- You may have created styles outside of a '.css.ts' context
- You may have incorrect configuration. See https://vanilla-extract.style/documentation/setup
Note: using VE via NextJS setup.
The key to keep in mind here is that vanilla works at build time. It outputs a plain CSS stylesheet, so trying to substitute values in at runtime isn't what it's built for.
If you have a clearly defined set of background colours that you want to use, you could use a recipe, or you could start to build up some atomic CSS with sprinkles.
If it needs to be truly dynamic, impossible to know at build time, you can take advantage of CSS variables using vanilla's dynamic package.

Target CSS child selector created by in material ui

I have styles like this:
const useStyles = makeStyles(theme => ({
root: {
margin: 5
},
container: {
backgroundColor: 'red'
},
active: {
// here I want to target the 'container' className I created above like
'& .container': {
backgroundColor: 'green'
}
}
});
I want to target the container className I created inside of the active className. The above won't work because in the DOM, MUI will generate a unique name so I won't be targeting the right class. Wasn't able to find any SO answer or blog or documentation addressing this.
$ rulename is used for this purpose. Here is the documentation of it on Material-UI.
CSS in JS documentation also explains this feature.
container: {
//other styles
},
active: {
"& $container": {
background: "green",
color: "#fff"
}
}
Here one thing which is important that for referencing 'containerrule, it should be defined in the rules object. trying to use"& $containerwithout defining thecontainerrule inside themakeStyles` will not work.
Here is the working demo:
You can refer using $
You will have to modify your DOM little bit such that the active className is not the parent of container. Instead add the active className to the conatiner element itself.
so your css style might look like below
const useStyles = makeStyles(theme => ({
root: {
margin: 5
},
container: {
backgroundColor: 'red',
'&$active': {
backgroundColor: 'green'
}
},
});
I think this is what you are looking for $rulename
How to Use $ruleName to reference a local rule within the same style sheet
In your case i think the solution would be
const useStyles = makeStyles(theme => ({
root: {
margin: 5
},
container: {
backgroundColor: 'red'
},
active: {
.container: {
backgroundColor: 'green'
}
}
});
Which should compile to
.root.container.active{}
and on the target tag taking a example of button here
<Button
classes={{
root: classes.root,
container: classes.container,
active: classes.active,
}}>
Havent worked with MUI yet but even in vue or react the way this is achived is by setting a dynamic name on the tag that is targeted via script.

Dynamic values in material ui's makeStyles

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

How to set breakpoints when overriding theme variables in createMuiTheme

I'm trying to set the default theme typography font sizes to change based on breakpoints. For example, when the breakpoint is at the {xs} value, change theme.typography.h4.fontSize to '1.5rem'. At all other breakpoints, leave it at the default value ('2.125rem').
I can do this easily in components using the following code example:
const useStyles = makeStyles(theme => ({
title: {
[theme.breakpoints.down('xs')]: {
fontSize: '1.5rem',
}
},
}))
However, this means having to add the same code to every single component that has <Typography variant='h4'> in it. If I decide to change the value from '1.5rem' to '1.25rem', I would need to locate every single instance of <Typography variant='h4'> and change it manually.
Is there any way to add breakpoints to createMuiTheme so it applies to all instances?
I have attempted the following, which does not work:
const defaultTheme = createMuiTheme()
const theme = createMuiTheme({
typography: {
h4: {
[defaultTheme.breakpoints.down('xs')]: {
fontSize: '1.5rem'
}
}
}
})
You can use custom breakpoints with createBreakpoints.
Here is an example changing the MuiButton
import createBreakpoints from '#material-ui/core/styles/createBreakpoints'
const customBreakpointValues = {
values: {
xs: 0,
sm: 576,
md: 768,
lg: 992,
xl: 1200,
},
}
const breakpoints = createBreakpoints({ ...customBreakpointValues })
const theme = createMuiTheme({
breakpoints: {
...customBreakpointValues,
},
components: {
MuiButton: {
styleOverrides: {
root: {
padding: '10px',
[breakpoints.up('lg')]: {
padding: '20px',
},
},
},
},
},
})
CORRECTION: Initially I indicated that your solution didn't work because you were using an impossible condition, but I was incorrect. "down" from xs is inclusive of xs, so it does what you would want (matches 0px to 600px).
I'm not sure what I did in my initial testing that led me astray, but one thing that can cause confusion is if you have multiple down thresholds. In my own testing, I had an easier time avoiding shooting myself in the foot (e.g. by having a breakpoints.down("xs") followed by a later breakpoints.down("sm") that trumped the "xs" settings) by using breakpoints.only.
From https://material-ui.com/layout/breakpoints/#breakpoints
xs, extra-small: 0px or larger
sm, small: 600px or larger
Here is an updated sandbox that shows a little more clearly what is happening:

Resources