Stepper vertical line detaches when label wraps over multiple lines? - reactjs

The text inside my MaterialUI Stepper // StepLabel sometimes wraps over multiple lines.
I need to keep the vertical StepConnectors attached the StepIcons regardless of the number of lines of text in the label.
I've tried other solutions such as using CSS pseudo tags, but I hit a wall every time I try to work those changes into our existing solution.
Massive thanks in advance to anyone who can help.
Sandbox
https://codesandbox.io/s/practical-chebyshev-4hktl?file=/src/App.js
Current Screenshot
Existing ThemeOptions
import {
ThemeOptions,
createTheme,
ThemeProvider,
CssBaseline
} from "#material-ui/core";
export const themeOptions: ThemeOptions = {
overrides: {
MuiStepper: {
root: {
backgroundColor: "transparent" // remove set background
}
},
MuiStepConnector: {
vertical: {
padding: 0,
width: 5,
marginLeft: 8 // half icon
},
lineVertical: {
top: "calc(-50%)",
bottom: "calc(50%)",
borderLeftWidth: "2px",
marginLeft: "-1px", // center (1/2 width)
marginTop: "-6px", // add -ve margin to top and bottom ...
marginBottom: "-6px", // ... to hide gap due to smaller icon
borderColor: "lightgrey",
"$active &, $completed &": {
borderLeftWidth: "4px",
marginLeft: "-2px",
borderColor: "blue"
}
}
},
MuiStepLabel: {
label: {
textAlign: "left",
fontSize: "1.25rem",
"&$active": {
fontWeight: 400
},
"&$completed": {
fontWeight: 400
}
},
iconContainer: {
paddingRight: 12
}
},
MuiStepIcon: {
root: {
display: "block",
fontSize: "1rem",
color: "lightgrey",
"&$completed": {
color: "blue"
},
"&$active": {
color: "blue"
}
}
}
}
};

Just in case anyone finds this in the future, we compromised on the ​implementation to deliver the task.
Instead of having a variable height on the MuiStepLabel, it was given a fixed height to keep the StepIcons the same distance apart. If you imagine the below screenshot with a different font size + spacing, it ended up looking OK, but not ideal.
Before
// src/Theme/index.tsx
export const themeOptions: ThemeOptions = {
overrides: {
MuiStepConnector: {
marginTop: "-6px",
marginBottom: "-6px",
}
MuiStepLabel: {}
}
}
After
// src/Theme/index.tsx
export const themeOptions: ThemeOptions = {
overrides: {
MuiStepConnector: {
marginTop: "-2px",
marginBottom: "-4px",
minHeight: "calc(24px + 0.5rem)",
},
MuiStepLabel: {
height: "1.25rem",
lineHeight: "1.25rem",
}
}
}
Sandbox
https://codesandbox.io/s/epic-bohr-0p7fj?file=/src/Theme/index.ts

Related

MUISelect style overwrite in global theme

I want to overwrite a specific style for multiple components. For now it works for all components, but not the the Select.
What I'm doing is:
MuiSelect: {
styleOverrides: {
select: {
background: themePalette.palette.background.paper,
marginLeft: '0rem',
borderRadius: '10rem',
},
iconOutlined: {
background: themePalette.palette.background.default,
color: themePalette.palette.primary.main,
borderRadius: '10rem',
},
},
variants: [
{
props: { size: 'small' },
style: {
borderRadius: '0.4rem',
select: {
borderRadius: '0.4rem',
},
iconOutlined: {
borderRadius: '0.4rem',
},
},
},
],
},
The style in the "styleOverrides" section get overwritten like expected. But the variant never is applied.
For other elements like TextField, ToggleButtonGroups, etc. it works. But somehow it does not work for the Select.
Also when I directly overwrite the same properties in the Select control via the sx prop, it's not applied.
sx={{
input: {
borderRadius: '0.4rem',
},
select: {
borderRadius: '0.4rem',
backgroundColor: theme.palette.grey[300],
},
borderRadius: '0.4rem !important',
}}
Here I also don't have any effect. The border radius is still unchanged at '10rem' like it's defined in the stylesOverrides.
Is this a bug, or am I doing something wrong for the Select?
style in theme props and sx work with css selectors. Not with pre-defined slots like styleOverrides
sx={{
'& .MuiSelect-select': {
...styles here,
...
}
}}

White-labeling in reactjs with Materail-UI and Tailwind

I have a react setup in which I am using Tailwind and Material-UI. I have a component library in the Storybook which has MUI Theme in it to style the variants like button outline. I am trying to find a way of how can I use these two things to make the react app white-labeled. Basically, Which properties I can set in my theme that it can be directly applied to the components by the user/providers/companies. Currently, my theme looks something like this in the component library.
import { createTheme, ThemeOptions } from '#mui/material/styles';
import { Colours } from '../common';
export const MyThemeOptions: ThemeOptions = {
palette: {
primary: {
main: Colours.primary,
},
secondary: {
main: Colours.secondary,
},
error: {
main: Colours.error,
},
warning: {
main: Colours.warning,
},
info: {
main: Colours.info,
},
success: {
main: Colours.success,
},
},
components: {
MuiButton: {
styleOverrides: {
root: {
borderRadius: '4px',
},
contained: {
padding: '4px 12px',
},
outlined: {
border: '1px solid #bdbdbd',
textTransform: 'none',
minWidth: 0,
color: '#212121',
},
outlinedSizeSmall: {
padding: '2px',
},
outlinedSizeMedium: {
padding: '6px',
},
outlinedSizeLarge: {
padding: '10px'
},
},
},
MuiButtonGroup: {
styleOverrides: {
grouped: {
minWidth: 0,
},
},
},
MuiCard: {
styleOverrides: {
root: {
boxShadow: '0 3px 7px 0 rgba(98, 125, 152, 0.16), 0 0 2px 0 rgba(36, 59, 83, 0.04)',
},
},
},
MuiToggleButton: {
styleOverrides: {
root: {
border: '1px solid #bdbdbd',
borderRadius: '4px',
textTransform: 'none',
color: '#212121',
minWidth: 0,
},
sizeSmall: {
padding: '2px',
},
sizeMedium: {
padding: '6px',
},
sizeLarge: {
padding: '10px',
}
}
}
},
};
const MyTheme = createTheme(MyThemeOptions);
export default MyTheme;
I am not able to find an article or tutorial or something which could lead me in a direction of how can I achieve the white labeling? If you know any knowledge asset in this direction, please share with me. Thank you!

How to extends classes in material UI createStyles

import { createStyles, Theme } from '#material-ui/core/styles';
export default (theme: Theme) => {
const { primary } = theme.palette;
return createStyles({
test1: {
fontSize: '30px',
},
test2: {
'& > div': {
color: primary.main,
marginTop: '20px',
},
},
});
};
Here I want to use class test1 in test2. How should I extend it?
You can use the dollar sign to reference the other selector when using JSS:
test1: {
width: 50,
height: 50,
backgroundColor: "pink",
"& $test2": {
backgroundColor: "red"
}
},
test2: {
width: 30,
height: 30
}
Reference
https://cssinjs.org/jss-plugin-nested?v=v10.8.1#use-rulename-to-reference-a-local-rule-within-the-same-style-sheet

Applying embedded styles to MUI components based on variants

I am trying to apply custom styling to the component based on its variants. However, a single component can have multiple variants specifying different style-properties. For this question, I will use code snippets from the Button component.
My wrapper of the Material UI Button component (defined here as MaterialButton):
import MaterialButton from '#material-ui/core/Button'
import './button-design-tokens.module.css'
export const Button: React.FC<ButtonProps> = (
props: ButtonProps
) => {
return (
<MaterialButton {...props}>{props.children}</MaterialButton>
)
}
I am trying to apply the following styles to this component in a Storybook environment using useStyles():
const useStyles = makeStyles({
contained: {
backgroundColor: 'var(--mdh-button-background-color)',
fontFamily: 'var(--mdh-button-font-family)',
'&.primary': {
color: 'var(--mdh-button-secondary-background-color)',
},
'&.secondary': {
color: 'var(--mdh-button-secondary-background-color)'
},
'&:hover': {
backgroundColor: 'var(--mdh-button-hover-background-color)',
color: 'var(--mdh-button-hover-text-color)'
},
'&:focus': {
backgroundColor: 'var(--mdh-button-focus-background-color)',
color: 'var(--mdh-button-focus-text-color)'
},
'&$disabled': {
backgroundColor: 'var(--mdh-button-disabled-background-color)'
}
},
outlined: {
borderRightColor: 'var(--mdh-button-background-color)',
borderLeftColor: 'var(--mdh-button-background-color)',
borderTopColor: 'var(--mdh-button-background-color)',
borderBottomColor: 'var(--mdh-button-background-color)',
'&:hover': {
borderRightColor: 'var(--mdh-button-hover-background-color)',
borderLeftColor: 'var(--mdh-button-hover-background-color)',
borderTopColor: 'var(--mdh-button-hover-background-color)',
borderBottomColor: 'var(--mdh-button-hover-background-color)'
},
'&:focus': {
borderRightColor: 'var(--mdh-button-focus-background-color)',
borderLeftColor: 'var(--mdh-button-focus-background-color)',
borderTopColor: 'var(--mdh-button-focus-background-color)',
borderBottomColor: 'var(--mdh-button-focus-background-color)'
}
},
outlinedPrimary: {
color: 'var(--mdh-button-background-color)'
},
outlinedSecondary: {
color: 'var(--mdh-button-secondary-background-color)'
},
textPrimary: {
color: 'var(--mdh-button-background-color)',
'&:hover': {
color: 'var(--mdh-button-disabled-background-color)'
},
'&:focus': {
color: 'var(--mdh-button-disabled-background-color)'
}
},
textSecondary: {
color: 'var(--mdh-button-secondary-background-color)',
'&:hover': {
color: 'var(--mdh-button-disabled-background-color)'
},
'&:focus': {
color: 'var(--mdh-button-disabled-background-color)'
}
}
})
As you can see, a Material UI button has the variants contained (a normal button), outlined (a button with only a coloured border) and text (a button consisting only of text). These variants can, in turn, have the primary, secondary and default variants which change the colour of the text inside the button.
The CSS variables seen in the JSON are defined in the css file imported in the Button wrapper. This file has the following contents:
:root {
--mdh-button-background-color: rgb(34, 123, 60);
--mdh-button-secondary-background-color: #EDBF07;
--mdh-button-focus-background-color: #9a6f1e;
--mdh-button-focus-text-color: white;
--mdh-button-hover-background-color: #9a6f1e;
--mdh-button-hover-text-color: white;
--mdh-button-disabled-background-color: #666;
--mdh-button-font-family: "TheMix", sans-serif;
}
.mdh-button {
background-color: var(--mdh-button-background-color);
font-family: var(--mdh-button-font-family);
}
.mdh-button--focus, .mdh-button:focus {
background-color: var(--mdh-button-focus-background-color);
color: var(--mdh-button-focus-text-color);
}
.mdh-button--hover, .mdh-button:hover {
background-color: var(--mdh-button-hover-background-color);
color: var(--mdh-button-hover-text-color);
}
.mdh-button--disabled {
background-color: var(--mdh-button-disabled-background-color);
}
As you can see, in order to style, for example, the outlined button in the primary variant, I would have to style this by combining the two variants in a class name (i.e. OutlinedPrimary). This is fine for minor changes, but I am developing a design system that is based on MUI and will have to re-style almost all the MUI components I am using in the system. This would lead to an insanely bloated and incomprehensible stylesheet for each component. Although this works, I am trying for a more compact and (in my humble opinion) logical approach. It is already defined in the JSON above, but I will highlight it below once more:
contained: {
backgroundColor: 'var(--mdh-button-background-color)',
fontFamily: 'var(--mdh-button-font-family)',
'&.primary': {
color: 'var(--mdh-button-secondary-background-color)',
},
'&.secondary': {
color: 'var(--mdh-button-secondary-background-color)'
},
'&:hover': {
backgroundColor: 'var(--mdh-button-hover-background-color)',
color: 'var(--mdh-button-hover-text-color)'
},
'&:focus': {
backgroundColor: 'var(--mdh-button-focus-background-color)',
color: 'var(--mdh-button-focus-text-color)'
},
'&$disabled': {
backgroundColor: 'var(--mdh-button-disabled-background-color)'
}
}
The primary variant is treated here as a 'subclass' of the contained variant of the Button. However, for some reason, this is not picked up by either Storybook or Material UI. I am applying the classes to the component like so:
const Template: Story<ButtonProps> = (args: any) => {
const classes = useStyles()
args.classes = {
contained: classes.contained,
outlined: classes.outlined,
// containedPrimary: classes.containedPrimary,
// containedSecondary: classes.containedSecondary,
textPrimary: classes.textPrimary,
textSecondary: classes.textSecondary,
outlinedPrimary: classes.outlinedPrimary,
outlinedSecondary: classes.outlinedSecondary
}
return <Button {...args}>Button</Button>
}
I have tried various and browsed through countless articles and blogs on the topic but have gotten none the wiser. Is there something I am missing? As far as I am aware, the syntax is correct.
Thank you in advance!

How can I use breakpoints inside createMuiTheme? Material UI & React.js

Maybe not the right approach but I want to create some 'global' styles for headings for example. Something like this:
const myTheme = createMuiTheme({
headings: {
h1: {
fontSize: 28,
// Obviously this does not work...
[theme.breakpoints.down('sm')]: {
fontSize: 24
},
},
h2: {
fontSize: 24,
}
}
}
then I can use them in my components like this:
const styles = (theme) => ({
myElement: {
...theme.headings.h1,
// ... other styles
}
}
This does work but the issue I face is I want the headings to be responsive and respect Material UI's breakpoints, but I can't use them inside the createMuiTheme itself? What is the way to do this correctly so I can just spread in my styles that INCLUDE the responsive styles all in one?
You can use the createBreakpoints method
Example:
// theme.js
import createBreakpoints from '#material-ui/core/styles/createBreakpoints'
import { createMuiTheme } from '#material-ui/core/styles'
const breakpoints = createBreakpoints({})
const theme = createMuiTheme({
overrides: {
MuiTab: {
root: {
[breakpoints.up('md')]: {
minWidth: '200px',
backgroundColor: 'yellow',
},
},
},
},
})
export default theme
(tested: material-ui 4.0.1)
V5 update
Preferred solution is to create an intermediate theme (source):
let theme = createTheme()
theme = createTheme(theme , {
h5: {
fontSize: "1.5", //24px
fontWeight: title.fontWeight,
fontFamily: sansSerif(title.fontFamily),
letterSpacing: title.letterSpacing,
lineHeight: "2.1rem", //34px
color: "#636e72",
[theme.breakpoints.between("xs", "sm")]: {
fontSize: "1.25rem", // 20px
lineHeight: "1.9rem", // 30px
},
[theme.breakpoints.between("sm", "md")]: {
fontSize: "1.4rem", //24px
lineHeight: "2rem", // 35px
},
},
})
If you used createBreakpoints: as pointed out by #Ricardo Canelas comment, createBreakpoints has simply moved, right import is now: import createBreakpoints from "#mui/system/createTheme/createBreakpoints". However, keep in mind that this is still a private API at the time of writing so can move/break at any version update.
Preferred solution is to use an intermediate theme.
From https://github.com/mui-org/material-ui/issues/18017#issuecomment-545914925
import { createMuiTheme } from "#material-ui/core/styles";
const theme = createMuiTheme();
theme.overrides = {
MuiTypography: {
hero: {
[theme.breakpoints.up('md')]:{
fontSize: '11rem',
background: 'red',
},
fontSize: '3.75rem',
lineHeight: '5rem',
fontWeight: 700,
},
},
};
This is a side note, but if you want to change the values of the breakpoints you can edit the breakpoints object created with createBreakpoints({}):
import createBreakpoints from '#material-ui/core/styles/createBreakpoints'
const breakpoints = createBreakpoints({})
// outputs {xs: 0, sm: 600, md: 960, lg: 1280, xl: 1920}
breakpoints.values.lg = 1024
// outputs {xs: 0, sm: 600, md: 960, lg: 1024, xl: 1920}
You could also add additional breakpoints in a similar way if you didn't want to edit the existing items:
breakpoints.values['xxl'] = 3000
// outputs {xs: 0, sm: 600, md: 960, lg: 1280, xl: 1920, xxl: 3000}
In my project the breakpoints that Material-UI has set (xs: 0, sm: 600, etc.) didn't line up with the ones I was using already in my project, so I had to change them.
const theme = createMuiTheme();
theme.typography.h3 = {
fontSize: '1.2rem',
'#media (min-width:600px)': {
fontSize: '1.5rem',
},
[theme.breakpoints.up('md')]: {
fontSize: '2.4rem',
},
};
https://material-ui.com/customization/typography/#responsive-font-sizes
You can also use something like this -
MuiInputBase: {
defaultProps: {
sx: {
fontSize: {
xs: '16px',
md: '14px',
},
},
},
},

Resources