Passing sx prop to a custom component - reactjs

I have a component that I use as a layout component, and in nearly all cases it works just fine, however there are one or two places where I need to be able to adjust the styles, and I would like to be able to do this by simply passing the exact styles that I need instead of adding some custom prop that will toggle them on or off.
The component looks like this:
const BlockLayout: React.FC<IProps> = ({
children,
id,
forceToBottom,
sxProps, // <--- What I want to add
}) => {
return (
<Box
id={id}
sx={[
{
backgroundColor: (theme) => theme.palette.background.paper,
mt: forceToBottom ? 'auto' : 1,
borderRadius: 0.5,
display: 'flex',
border: '1px solid rgba(0, 0, 0, 0.1)',
flexWrap: 'wrap-reverse',
},
sxProps, //<--- How I could use it?
(theme) => ({
...(theme.palette.mode === 'dark' && {
border: `1px solid ${lighten(
theme.palette.background.paper,
0.15
)}`,
}),
}),
]}
>
{children}
</Box>
)
}
How can this be done, and what type do the props need to have?

In the documentation they just cast the type to const.
You can add them as follows using the spread operator:
},
sxProps && ...sxProps,
(theme) => ({

Related

How to use conditional styles with MUI v5 using emotion styled

I'm migrating from MUI v4 to v5. In v4 I was using clsx with TextField to add conditional styles.
export const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
// ...
},
valid: {
"& fieldset": {
borderColor: theme.palette.success.main,
borderWidth: 2
}
}
})
);
const classes = useStyles();
<TextField
{...props}
className={clsx(classes.root, { [classes.valid]: isValid })}
/>
I'm trying to find a similar approach in MUI v5. Is there any alternative for conditional styles in MUI v5 other than with clsx and makestyles.
Let me know if more information is required.
There are multiple ways to do that:
1. Conditional operator
Use this if you want to conditionally set a property based on a boolean value.
const Box1 = styled(Box, {
shouldForwardProp: (prop) => prop !== "showBorder"
})(({ showBorder }) => ({
border: showBorder ? "solid red 5px" : "none"
}));
<Box1 />
<Box1 showBorder />
2. Dictionary
Use this if you want to conditionally set a property based on multiple values.
import { styled, darken } from "#mui/material/styles";
const colors = {
hauntedForest: "#0b5b38",
redLust: "#b20608",
spaceExplorer: "#1244a1",
default: "#000000"
};
const Box2 = styled(Box, {
shouldForwardProp: (prop) => prop !== "variant"
})(({ variant }) => ({
backgroundColor: colors[variant] ?? colors.default,
border: "5px solid " + darken(colors[variant] ?? colors.default, 0.3)
}));
<Box2 variant="hauntedForest" />
<Box2 variant="redLust" />
<Box2 variant="spaceExplorer" />
<Box2 />
3. Short-circuit evaluation + Spread operator
Use this if you want to conditionally set multiple properties.
const Box3 = styled(Box, {
shouldForwardProp: (prop) => prop !== "isFancy" && prop !== "isFancyBorder"
})(({ theme, isFancy, isFancyBorder }) => ({
...(isFancy && {
borderRadius: theme.shape.borderRadius,
boxShadow: "0 4px 6px gray, 0 1px 3px rgba(0, 0, 0, 0.08)",
backgroundImage: "linear-gradient(90deg, #be5af7, #165b91)"
}),
...(isFancyBorder && {
backgroundColor: "transparent",
border: "5px solid transparent",
borderImage: "linear-gradient(90deg, #be5af7, #165b91)",
borderImageSlice: 1
})
}));
<Box3 isFancy />
<Box3 isFancyBorder />
All of the methods above can also be applied when using sx props since they use JS object to describe the styles.
Live Demo
This seem to work for me
Using sx
sx={{ px: variable ? 8 : null }}
sx with breakpoint
sx={{ px: { md: variable ? 8 : null } }}
prop
<Typography align={variable ? 'center' : 'inherit'}>
Using className
className={ variable ||'class-name'}

how to remove the outline and box shadow on input tag in react-select

I want to remove the blue outline and box-shadow when the input tag is active.
You need to pass custom styles prop.
Something like this
const customStyles = {
control: (base, state) => ({
...base,
height: "100%",
minHeight: "100%",
border: 0,
boxShadow: "none",
}),
dropdownIndicator: (base, state) => {
return {
...base,
};
},
placeholder: (base, state) => ({
...base,
}),
singleValue: (base, state) => ({
...base,
}),
option: (base, state) => ({
...base,
}),
};
return (
<Select
//REST OF YOUR PROPS
styles={customStyles}
isSearchable={false} //This gets rid of the default cursor
/>
)
Try playing around with the customStyles object to style it further :)
The default styles are derived from a theme object, which you can mutate like styles.
The theme object is available for the styles functions as well.
<Select
label="Single select"
options={user}
theme={theme => ({
...theme,
borderRadius: 'none',
colors: {
...theme.colors,
primary25: 'primary',
primary: 'neutral5',
},
})}
/>
const style = {
control: base => ({
...base,
border: 0,
boxShadow: 'none'
})
};
Old question but the blue outline is a drop-shadow on the input field itself (at least was in my case), I ended up just adding a custom class to the select field like
<ReactSelect
title = { __( 'Title', 'lang' ) }
className = { 'your-custom-class' }
...
and then styling it out with
.your-custom-class input {
box-shadow: none;
}

how to remove padding-top in menu drop-down react-select?

how to remove padding-top in menu drop-down react-select?
const customStyles = {
indicatorSeparator: styles => ({ ...styles, display: "none" }),
option: (provided, state) => ({
...provided,
fontSize: 16,
height:"40px",
paddingLeft: "11px",
":firstChild": {
margin: "10px",
padding: "10px",
borderRadius: "10px 10px 10px 10px"
}),
<Select
styles={customStyles}
defaultValue={[colourOptions[2], colourOptions[3]]}
isMulti
name="colors"
options={colourOptions}
className="basic-multi-select"
classNamePrefix="select"
/>
enter image description here
https://codesandbox.io/s/react-codesandboxer-example-90zz6
The default margin-top between the menu list and the select box can be removed easily with the props styles like this:
const styles = {
menu: base => ({
...base,
marginTop: 0
})
}
Live example here.
You should set the styles for the menuList style key according to react-select docs.
menuList: (provided, state) => ({
...provided,
paddingTop: 0,
paddingBottom: 0,
}),
use this use multi inline style by using {[firststyle,secandstyle]}
and define the second style bellow the first style as shape following
`const nopadinng={
paddingTop:0};`
and remove the classname
// remove the className
className="basic-multi-select"
const nopadinng={
paddingTop:0};
styles={[customStyles,nopadinng]}

Applying specific theme for react material-table

I'm trying to integrate react material-table (https://github.com/mbrn/material-table) with my project.
I want to update the styling/theme.
I used something like.
<MaterialTable options={{
rowStyle: x => {
if ( x.id % 2 ) {
return { backgroundColor: "#f2f2f2" }
}
},
'headerStyle' : {
backgroundColor: 'red',
color: theme.palette.common.white
}
}}
columns={columns}
data={data}
title="New Table"
/>
However I want to have a generic styling and theme like
const CustomTableCell = withStyles(theme => ({
head: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white,
},
body: {
fontSize: 14,
},
}))(TableCell);
Basically i want to have something like CustomMaterialTable which is nothing but my theme/style.
Striping the table rows.
In the above code snippet, I used a logic to have striped rows.
if ( x.id % 2 ) {
return { backgroundColor: "#f2f2f2" }
}
Since my table will be having sorting, I want the it to be on a auto generated row id rather than x.id (where x is my data).
I want to use rtl and text in multiple languages based on the language selection (dynamic).
You can overrides components. Look at example: https://mbrn.github.io/material-table/#/docz-examples-10-example-component-overriding
Can you try x.tableData.id instead of x.id, please?
You should use material-ui theme with direction (ltr or rtl): https://material-ui.com/customization/themes/
you can use material-UI makeStyles for changing material-table theme.
This example when I'm changing the look for material-table
I implemented striped rows using
'&:nth-child(even)': {
backgroundColor: '#FAF7FA',
},
because when using rowStyle and after changing the table sorting, the stripped rows remain attached to their main fields.
Here is the full example:
export const useClasses = makeStyles(({ palette }) => ({
root: {
borderTopRightRadius: '12px',
borderTopLeftRadius: '12px',
boxShadow: '0px 5px 40px rgb(0 0 0 / 10%)',
fontFamily: 'Montserrat',
overflow: 'hidden',
'& .MuiPaper-root ': {
boxShadow: 'none',
},
'& .MuiTable-root': {
color: palette.text.textPrimary,
'& .MuiTableHead-root': {
'& .MuiTableRow-head': {
'& .MuiTableCell-head': {
background: 'rgba(90, 0, 90, 0.09)',
color: palette.text.textPrimary,
},
},
},
'& .MuiTableRow-root': {
'&:nth-child(even)': {
backgroundColor: '#FAF7FA',
},
},
},
},
}));

How can I disable multiline for autocomplete material-ui demo?

Country select of
autocomplete demo at material-ui
uses react-select and material-ui controls,
shows multiline text, select control changes it's dimensions when country doesn't fit in one line.
I see this behaviour at CodeSandbox when I decrease width of web browser.
How can I modify demo so that country will always fit in one line,
select control will not change it's dimensions?
TextField has props multiline, rows and rowsMax props that can be changed.
If that isn't what you need then you could add the following css to the text in the TextField so the text does not wrap:
overflow: hidden;
white-space: nowrap;
I managed this by mixing a few different things:
First create a class like so:
const useStyles = makeStyles((theme: Theme) =>
createStyles({
closed: {
flexWrap: "nowrap",
overflowX: "hidden",
},
// Add a linear gradient behind the buttons and over the Chips (if applies)
endAdornment: {
background:
"linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.6) 22%, rgba(255,255,255,1) 60%)",
bottom: 0,
display: "flex",
alignItems: "center",
right: "0 !important",
paddingRight: 9,
paddingLeft: theme.spacing(2),
top: 0,
},
})
);
Then in your static function add this :
const onOpenChange = (open: boolean | null) => {
setIsOpen(open);
};
const inputStyle = clsx({
[classes.closed]: !isOpen, //only when isOpen === false
});
Finally on the Autocomplete component itself use:
classes={{ inputRoot: inputStyle, endAdornment: classes.endAdornment }}
onOpen={() => onOpenChange(true)}
onClose={() => onOpenChange(false)}
If you are wondering how to make each option be displayed in just one line with ellipsis, you can do the follow:
<Autocomplete
...
getOptionLabel={(option: any) => `${option.label} (${option.code})`}
renderOption={(option) => (
<React.Fragment>
<div style={{ textOverflow: 'ellipsis', overflow: "hidden", whiteSpace: "nowrap" }}>
{option.label} ({option.code})
</div>
</React.Fragment>
)}
...
/>
For the Country Demo example, you can check what I did here: https://codesandbox.io/s/autocomplete-with-ellipsis-i8hnw

Resources