How to override default MaterialUI styles with React? - css

I canĀ“t style the Outline Select component with the properties I want when using Material UI with react, how can override default styles?
I have used withStyles but I can't achieve the expected look and feel.
For example if I change the border using a custom Input in the Select, then the Label doesn't work as expected, the border and the label touch instead of the label like floating.
import { createStyles, makeStyles, withStyles } from '#material-ui/core/styles';
import OutlinedInput from '#material-ui/core/OutlinedInput';
import InputLabel from '#material-ui/core/InputLabel';
import MenuItem from '#material-ui/core/MenuItem';
import FormControl from '#material-ui/core/FormControl';
import Select from '#material-ui/core/Select';
export const StyledSelect = ({ name, value, onChange, items }) => {
const classes = useStyles();
const inputLabel = React.useRef<HTMLLabelElement>(null);
const [labelWidth, setLabelWidth] = React.useState(0);
React.useEffect(() => {
setLabelWidth(inputLabel.current!.offsetWidth);
}, []);
return (
<FormControl variant="outlined" />
<InputLabel
ref={inputLabel}
htmlFor={name}
>
{name}
</InputLabel>
<Select
value={value || ''}
onChange={onChange}
input={<CustomInput labelWidth={labelWidth} />}
>
{items.map(item => {
return (
<MenuItem key={item.key} value={item}>
{item.label}
</MenuItem>
);
})}
</Select>
</FormControl>
);
};
const CustomInput = withStyles(theme => ({
root: {
'label + &': {
/* marginTop: theme.spacing(3), */
},
},
/* label: {
width: '',
}, */
input: {
'borderRadius': 4,
'position': 'relative',
/* 'backgroundColor': theme.palette.background.paper, */
'border': '2px solid #ced4da',
/* 'fontSize': 16, */
/* 'transition': theme.transitions.create(['border-color', 'box-shadow']), */
// Use the system font instead of the default Roboto font.
'fontFamily': [
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'"Helvetica Neue"',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
].join(','),
'&:hover': {
border: '2px solid red',
borderRadius: 4,
},
'&:focus': {
border: '2px solid #ced4da',
borderRadius: 4,
borderRadius: 4,
borderColor: "#80bdff",
boxShadow: "0 0 0 0.2rem rgba(0,123,255,.25)"
},
},
}))(OutlinedInput);
I expect to style only what I need and don't break the functionality of the OutlineSelect component.

When you click an input field in material UI the class names is changed and a different style is applied to the label field.
More specifically the class .MuiInputLabel-shrink is added to the label element. If you want to target this styling, you must reference this class in your withStyles()
See the imput-label API here:
https://material-ui.com/api/input-label/#main-content

Related

Styling the DatePicker from MUI

I'm using a DatePicker component from Mui Lab and I am trying to style the Calendar component by adding some border or background color. I used the PaperProps prop for DatePicker but it's not styling it. Trying to understand why I cant just use an SX prop for it
this is the calendar where i want to add a border to
import PropTypes from 'prop-types';
import { TextField } from '#material-ui/core';
import { alpha } from '#material-ui/core/styles';
import DatePicker from '#material-ui/lab/DatePicker';
import { AppBorderStyle } from '../theme';
export const DateField = (props) => {
const {
error,
fullWidth,
helperText,
label,
onChange,
onBlur,
placeholder,
disabled,
value,
name,
...other
} = props;
return (
<DatePicker
PopperProps={{
sx: {
'& .MuiPaper-root': {
backgroundColor: 'red',
border: '1px solid black',
}
}
}}
onChange={onChange}
renderInput={({ InputProps, ...rest }) => (
<TextField
{...rest}
disabled={disabled}
onBlur={onBlur}
name={name}
error={error}
fullWidth={fullWidth}
helperText={helperText}
label={label}
placeholder={placeholder}
sx={{
'& .MuiFilledInput-root': {
backgroundColor: 'background.paper',
borderRadius: 1,
border: AppBorderStyle,
px: 1.5,
py: 0.75,
transition: (theme) => theme.transitions.create([
'border-color',
]),
'&:hover': {
backgroundColor: 'background.paper'
},
'&.Mui-focused': {
backgroundColor: 'background.paper',
boxShadow: (theme) => `${alpha(theme.palette.primary.main,
0.25)} 0 0 0 0.2rem`
},
'& .MuiFilledInput-input': {
fontSize: 14,
height: 'unset',
lineHeight: 1.6,
p: 0
},
'&.Mui-disabled': {
backgroundColor: 'action.disabledBackground',
boxShadow: 'none',
borderColor: alpha('#D6DBE1', 0.5)
}
}
}}
variant="filled"
InputProps={{
disableUnderline: true,
...InputProps
}}
InputLabelProps={{
shrink: true,
sx: {
color: 'text.primary',
fontSize: 14,
fontWeight: 500,
mb: 0.5,
position: 'relative',
transform: 'none'
}
}}
/>
)}
value={value}
{...other}
/>
);
};
DateField.defaultProps = {
disabled: false,
};
DateField.propTypes = {
disabled: PropTypes.bool,
error: PropTypes.bool,
fullWidth: PropTypes.bool,
helperText: PropTypes.string,
label: PropTypes.string,
name: PropTypes.string,
onChange: PropTypes.func.isRequired,
onBlur: PropTypes.func.isRequired,
placeholder: PropTypes.string,
value: PropTypes.instanceOf(Date)
};
I noticed you're using depecrated version of mui as you can check here. For newer versions of material UI components, we import material components from #mui and not from #material-ui.
I'm not sure if the classes are the same in your version or not. But the issue for your case looks like you are targeting the wrong class to add a border. You need to target MuiPickersPopper-root class to change the border.
PopperProps={{
sx: {'&.MuiPickersPopper-root': {border: '4px solid red'},},
}}
I created a solution of DatePicker with the border here. Cheers!

How to add a state and a list of links displayed in react js and storybook?

I need to have the accordion component that will change over a state when user clicks on the icon.
When user clicks on the icon, the icon and color of the title should get changed and list of links should display.
So far I managed to add onClick option to the component but what will be the best approach to achieve the result of a list displaying over a click?
How to make the icon change over click and display a list with storybook?
Could you please kindly give some advise?
Any help would be appreciated.
I already added two options for the icon, so I think I can add somehow a state to it and make it display on storybook, but not really sure how :(
Here is the component:
import { string, oneOf, func, bool } from "prop-types"
import Icon, { icons } from "design-system/components/icon"
import * as Styled from "./Button.styled"
const Button = ({
href,
text,
iconStart,
iconEnd,
variant,
color,
size,
active,
onClick,
}) => (
<Styled.Component
as={href ? `a` : `button`}
variant={variant}
color={color}
size={size}
href={href}
onClick={onClick}
>
{iconStart && (
<Styled.Icon>
<Icon name={iconStart} size={size} />
</Styled.Icon>
)}
<Styled.Text variant={variant} color={color} active={active}>
{text}
</Styled.Text>
{iconEnd && (
<Styled.Icon>
<Icon name={iconEnd} size={size} />
</Styled.Icon>
)}
</Styled.Component>
)
Button.propTypes = {
text: string.isRequired,
href: string,
iconStart: oneOf(Object.keys(icons)),
iconEnd: oneOf(Object.keys(icons)),
variant: oneOf(["fill", "border", "text", "textLine"]),
color: oneOf(["primary", "black", "white"]),
size: oneOf(["small", "medium", "large"]),
active: bool,
onClick: func,
}
Button.defaultProps = {
href: null,
iconStart: null,
iconEnd: null,
variant: "fill",
color: "primary",
size: "medium",
active: null,
onClick: null,
}
export default Button
Here are the styles:
import styled from "#emotion/styled"
import { css } from "#emotion/react"
import theme from "design-system/theme"
const sizes = {
small: {
typography: theme.typography.desktop.bodySmall,
padding: "8px 32px",
},
medium: {
typography: theme.typography.desktop.h5,
padding: "10px 40px",
},
large: {
typography: theme.typography.desktop.h4,
padding: "12px 48px",
},
}
const colors = {
primary: {
mainColor: theme.colors.primary[500],
filledText: theme.colors.neutrals[100],
},
black: {
mainColor: theme.colors.grey[600],
filledText: theme.colors.neutrals[100],
},
white: {
mainColor: theme.colors.neutrals[100],
filledText: theme.colors.primary[300],
},
}
export const Component = styled.a`
text-align: center;
border-radius: 10px;
padding: 19px;
position: relative;
color: ${({ theme }) => theme.colors.grey[600]};
background-color: ${({ theme }) => theme.colors.complementary[100]};
`
export const Text = styled.span`
${({ variant }) =>
variant === "textLine" &&
css`
text-decoration: underline;
`}
${({ active, variant, color }) =>
active &&
variant === "text" &&
css`
border-bottom: 2px solid ${colors[color].mainColor};
`}
`
export const Icon = styled.span`
display: inline-flex;
align-items: center;
justify-content: center;
`
and storybook:
import { Meta, Canvas, Story, ArgsTable } from "#storybook/addon-docs"
import Button from "design-system/components/button"
import Icon from "design-system/components/icon"
<Meta title="Components/Button" component={Button} />
# Button
<Canvas>
<Story
name="Overview - button icon end"
args={{
text: "O nas",
iconEnd: "arrowDown",
variant: "fill",
size: "medium",
}}
>
{Template.bind()}
</Story>
</Canvas>
<ArgsTable />
export const Template = (args) => <Button {...args} />

Material UI: How can I change the border color of the Select component?

I am trying to customize the Select component from Material UI.
This is what it looks like:
However, when the select component is focused, I want to change the border-color from material UI's blue to a custom red color.
I tried setting the styles but it doesn't do anything at all
import FormControl from '#material-ui/core/FormControl';
import InputLabel from '#material-ui/core/InputLabel';
import MuiSelect from '#material-ui/core/Select';
import MenuItem from '#material-ui/core/MenuItem';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
select: {
borderColor: '#FF0000', //<------------ this does nothing
},
}));
const Select = () => {
const classes = useStyles();
return (
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel>Months</InputLabel>
<MuiSelect label="Months" className={classes.select}>
<MenuItem value="1">January</MenuItem>
<MenuItem value="2">February</MenuItem>
<MenuItem value="3">March</MenuItem>
<MenuItem value="4">April</MenuItem>
</MuiSelect>
</FormControl>
);
};
Select.propTypes = {};
export default Select;
Try this:
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
select: {
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
borderColor: 'red',
},
},
}));
If someone is interested in the latest version of MUI 5.
import {
Select,
} from '#mui/material';
import { SxProps } from '#mui/material/styles';
import classes from './component.module.css';
const styles: SxProps = {
select: {
'.MuiOutlinedInput-notchedOutline': {
borderColor: '#color',
},
'&:hover .MuiOutlinedInput-notchedOutline': {
borderColor: '#color',
borderWidth: '0.15rem',
},
},
};
<Select
variant="outlined"
sx={styles.select}
inputProps={{
classes: {
icon: classes.icon,
},
}}
>
For the icon, you can create a separate file component.module.css
.icon {
fill: #color;
}

custom styling for material UI tooltip arrow?

I would like to add a custom style for Material UI tooltip arrow but I can not set the border color and the background color.
This is the configuration I have - react:
const useStylesBootstrap = makeStyles(theme => ({
arrow: {
// color: '#E6E8ED',
border: '1px solid #E6E8ED',
},
tooltip: {
backgroundColor: theme.palette.common.white,
border: '1px solid #E6E8ED',
color: '#4A4A4A'
},
}));
This is what I want to achieve:
I want to apply a gray color in the triangle border and the background will be white.
On the arrow configuration, the border config will not work, it will apply a border color in the square that's housing the triangle. Without material UI, the issue could be solved using the pseudo :before and :after to achieve the desired output. I would like to know if there is a solution to this using material UI custom configuration. Not too familiar with Material UI, your help will be appreciated
You are right, You need to override &:before pseudoselector like this.
Here is the code sandbox project link
import React from "react";
import Button from "#material-ui/core/Button";
import Tooltip from "#material-ui/core/Tooltip";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles(theme => ({
arrow: {
"&:before": {
border: "1px solid #E6E8ED"
},
color: theme.palette.common.white
},
tooltip: {
backgroundColor: theme.palette.common.white,
border: "1px solid #E6E8ED",
color: "#4A4A4A"
}
}));
export default function ArrowTooltips() {
let classes = useStyles();
return (
<Tooltip
title="Add"
arrow
classes={{ arrow: classes.arrow, tooltip: classes.tooltip }}
>
<Button>Arrow</Button>
</Tooltip>
);
}
See tooltip css. Use arrow and &::before to target the arrow and apply your styles. (note the double :: there)
makeStyles - style
arrow: {
fontSize: 20,
color: "#4A4A4A",
"&::before": {
backgroundColor: "blue",
border: "2px solid red"
}
}
JSX
<Tooltip classes={{ arrow: classes.arrow }} title="Delete" arrow>
<IconButton aria-label="delete">
<DeleteIcon />
</IconButton>
</Tooltip>
Working demo
FYI on material ui 5 makestyles is deprecated.
Because tooltip is in portal you cannot style it directly
const StyledTooltip = styled<typeof Tooltip>(({ className, ...props }) => (
<Tooltip {...props} classes={{ popper: className }} />
))``;
then in reder function you can use sx, by setting popper you can access child props via sx
<StyledTooltip
open
arrow
sx={{
'& .MuiTooltip-arrow': {
background: 'red',
},
}}
/>
Using the official MUI customization examples:
https://mui.com/material-ui/react-tooltip/#customization
const LightTooltip = styled(({ className, ...props }: TooltipProps) => (
<Tooltip {...props} classes={{ popper: className }} />
))(({ theme }) => ({
[`& .${tooltipClasses.arrow}`]: {
color: theme.palette.common.white,
"&::before": {
backgroundColor: theme.palette.common.white,
border: "1px solid #999"
}
},
[`& .${tooltipClasses.tooltip}`]: {
backgroundColor: theme.palette.common.white,
color: 'rgba(0, 0, 0, 0.87)',
boxShadow: theme.shadows[1],
fontSize: 11,
},
}));
We can do a custom styling in the following way
import Tooltip from '#material-ui/core/Tooltip'
import { withStyles } from '#material-ui/core/styles'
const HtmlTooltip = withStyles(theme => ({
arrow: {
'&::before': {
color: 'white'
}
},
tooltip: {
backgroundColor: '#f5f5f9',
boxShadow: theme.shadows[8],
color: 'rgba(0, 0, 0, 0.87)',
fontSize: 14,
maxWidth: 800,
padding: 0,
},
tooltipPlacementTop: {
margin: '4px 0',
},
}))(Tooltip)
<HtmlTooltip
title={
<React.Fragment>
<Typography color="inherit">Tooltip with HTML</Typography>
<em>{"And here's"}</em> <b>{'some'}</b> <u>{'amazing content'}</u>.{' '}
{"It's very engaging. Right?"}
</React.Fragment>
}
>
<Button>HTML</Button>
</HtmlTooltip>

ReactJS material makeStyles

I have my own theme, I can theming well.
Right now I have three different styles with material UI tabs. That's why I need to change styles using makeStyles.
This is example of tab I need to change
...
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
width: "100%",
backgroundColor: theme.pallete.primary
},
tabs: {
/// some styles
}
...
}
));
...
<Tabs
...someProps
className={classes.tabs}
>
element inside tab have such classes:
<button class="MuiButtonBase-root MuiTab-root MuiTab-textColorSecondary Mui-selected MuiTab-labelIcon">
I have tried to edit styles the same way as
... = createMuiTHeme ({
overrides: {
...some overrides
}
in my case:
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
width: "100%",
backgroundColor: "#121D42",
MuiButtonBase: {
root: {
///some styles
},
}
},
...
but it doesn't work with makeStyles
So how can I edit buttons inside tabs using makeStyles(), is it possible? Or help me with solution please
I have found a solution for now.
Using Styled Components and with creating a styled element - we can change styles easier. We should StylesProvider
const NewButton = styled(({styledComponentProp, ...rest}) => (
<Button classes={{label: 'label'}} {...rest}/>
))`
.label {
color: blue;
font-size: ${props => props.styledComponentProp};
}
`
export const BlueButton = styled(props => {
return (
<StylesProvider injectFirst>
<NewButton variant="contained" styledComponentProp="20px"> Red Labeled Button </NewButton>
</StylesProvider>
);
})`
`;
But have we any better solutions?

Resources