How combine styled-system with react material? - reactjs

I wanna use styled-system in my project which is the admin panel. I built project basing on React Material and I have a lot of different forms with inputs, selects, checkboxes and so on. In many places I have to set some margins/paddings for elements and I make this moment with some custom Box component, that uses styled-system functions (space, color, etc). But it the end I got a rather cumbersome structure something like this :
<Box>
<Box mb={10}>
<Box mr={2}><TextField/></Box>
<Box mr={2}><TextField/></Box>
<Box mr={2}><TextField/></Box>
</Box>
<Box>
<Box mr={2}><Select/></Box>
<Box mr={2}><Select/></Box>
<Box mr={2}><Select/></Box>
</Box>
</Box>
And it's just a little part of the component. I think, in this situation it would be good to create some wrapper around TextField/Select components which will add styled-system functions to components.
And then use them like :
<Box>
<Box mb={10}>
<TextField mr={2}/>
<TextField mr={2}/>
<TextField mr={2}/>
</Box>
<Box>
<Select mr={2}/>
<Select mr={2}/>
<Select mr={2}/>
</Box>
</Box>
But then I understand that react-material has a lot of components and what I have to do? Override all of them to have some similar style? Or what way can be more comfortable?

So what you are asking for can definitely be achieved without adding that much noise to the markup.
First off, the styled markup works for all material-ui components. Luckily, styled-system is ALSO interoperable with styled-components. So you can do this
const StyledButton = styled(TextField)`
color: red;
// to access theme in a styled-system way
${get("mt", 3)};
`;
That accessor called get is a little unique, it comes from this package. It allows you to use all the styled-system flavoured keys inside of a styled-component.
If you wanted inline props for all the material components, like you described, its a little more involved. You would need to wrap each component with the proper decorators that enable such inline props. Creating basically a shadow library.
import styled from 'styled-components';
import { variant, space, layout, position } from 'styled-system';
export default styled(TextField)(
position,
layout,
space,
// whatever else
);
Check out the official build-a-box tutorial for better insight.

Related

How fix input label of OutlinedInput

I'm playing with material ui and build a project and I needed make a TextField with mask
with react-imask:
https://mui.com/en/material-ui/react-text-field/#integration-with-3rd-party-input-libraries
But I tried with OutlinedInput but the label crashes:
<FormControl variant="standard">
<InputLabel htmlFor="formatted-text-mask-input">react-imask</InputLabel>
<OutlinedInput
value={values.textmask}
onChange={handleChange}
name="textmask"
id="formatted-text-mask-input"
inputComponent={TextMaskCustom as any}
/>
</FormControl>
Empty
Filled
Codesandbox box
https://codesandbox.io/s/problem-with-3rd-party-input-libraries-cygxss?file=/demo.tsx
Codesandbox result link:
https://cygxss.csb.app/
Is there any reason you don't just use a TextField with variant set to "outlined"?
The MUI example is just showing different methods of using their components and the FormControl composition is done in greater complexity within TextField.
Solution
<TextField
label="react-imask"
id="formatted-text-mask-input"
name="textmask"
value={values.textmask}
onChange={handleChange}
InputProps={{
inputComponent: TextMaskCustom as any
}}
/>
Brief Look at Form Control
It appears as though you have an OutlinedInput but are telling the FormControl it is "standard", fixing this puts the label in the right spot, but it does not properly break the border of the fieldset as intended.
If you need to manually control the composition of the individual parts (FormControl, InputLabel, OutlinedInput, etc) you can see how MUI compose TextField in GitHub.

Custom Text Field with icon at start of the Text Field with the variant type "outlined" in material-ui

Everyone
I have been trying to implement an icon inside the TextField component at the start of it using material-ui.
I believe that the reader knows about the Material UI library. I stuck to using Version 4 for this project.
I did find a few things for achieving this and I did try it. But it's working on some conditional basis. That is if I try to style the notchedOutline of the TextField like giving it a borderRadius or something the icon is not getting visible. Though after inspecting the element I do find it there. I did try to change the color and everything but nothing is working.
Here is what I need :
Image Describing my need
and here is what I am getting:
The coded output image
And here is the code that I have tried.
import {....,TextField,InputAdornment } from "#material-ui/core";
.........
<TextField
variant="outlined"
InputProps={{
startAdornment: (<InputAdornment position="start"><img src={someImage} /></InputAdornment>)
}}
classes={{
root classes.textField,
}}
fullWidth
/>
........
Can someone please help me in solving the same.
Thank you!!
There's something wrong with the image you use as a child inside <InputAdornment/> component. Make sure you import it correctly. However, according to docs, <InputAdornment/> expects as child - The content of the component, normally an IconButton or string.
Therefore, you should install #material-ui/icons package and use their icons instead on an img :
import MailIcon from '#material-ui/icons/Mail';
...
InputProps={{
startAdornment: <InputAdornment position="start"><MailIcon/></InputAdornment>,
}}
Demo

Override component styles via Box

MUI's docs say that it's possible for a Box wrapper to override its child's styling with the clone option, like this:
<Box color="red" clone>
<Button>Click me</Button>
</Box>
As far as I understand, it's supposed to cloneElement its child and inject the styles. However, it doesn't seem to work at all - not with buttons, nor typographies, nor any other component.
Hmm yes clone has some issues seems it will be removed in v5
https://github.com/mui-org/material-ui/issues/18496#issuecomment-557835104
for the moment could use like but not good :(
<Box color="red">
<Button color='inherit'>Click me</Button>
</Box>

Responsive and split layout

I started a project with react-splitter-layout and material ui library.
I would like to find a way to create responsive components, with material ui Grid or Box component
I encounter a problem with responsive, I would like my left panel to be responsive (use of xs / md / lg) with Grid component based on the size of the container (not window size), as you can see in the example below , this is not the case. It's use the viewport size. (I know it's normal because of media queries).
Here the code sample : https://codesandbox.io/s/material-demo-i04rr?file=/demo.js (recommended to open the rendering in a new tab to see the problem)
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Paper from "#material-ui/core/Paper";
import Grid from "#material-ui/core/Grid";
import SplitterLayout from "react-splitter-layout";
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1
},
paper: {
padding: theme.spacing(2),
textAlign: "center",
color: theme.palette.text.secondary
}
}));
export default function CenteredGrid() {
const classes = useStyles();
return (
<SplitterLayout>
<div className={classes.root}>
<Grid container spacing={3}>
<Grid item xs={4} md={6} lg={8}>
<Paper className={classes.paper}>xs=3</Paper>
</Grid>
<Grid item xs={4} md={4} lg={2}>
<Paper className={classes.paper}>xs=3</Paper>
</Grid>
<Grid item xs={4} md={2} lg={2}>
<Paper className={classes.paper}>xs=3</Paper>
</Grid>
</Grid>
</div>
<div>Panel 2</div>
</SplitterLayout>
);
}
Anyone have a solution to this problem ?
Best regards,
EDIT
I also posted in material ui github https://github.com/mui-org/material-ui/issues/25189
This is one of my question when I started using material-UI or any CSS framework.
Material-UI currently supports almost cases you need especially for responsive, and I never use any other library/framework for responsive. First, you know that all xs, sm, md are based on screen size, not on their container.
Then, the problem here is how did you called a "container"? When you work with material-UI, you should layout everything based on screen size instead of a specific container. Because your "container" you are think about doesn't have any meaning in responsive. It just help you solve the layout problem.
To be honest, just change your mind, thinking in the way of Material-UI, and everything about responsive become easily.

Change the position of Tabs' indicator in Material UI

I'm trying to set the position of the indicator to the top of TAB instead of the bottom like:
I checked and tried to update CSS but it didn't work. I'm new to react so I couldn't customize the components.
I create an example in codesandbox that I share with you.
https://codesandbox.io/s/usage-p0y9t?file=/index.js
You can pass to Tabs the property classes to override internal classes.
In this case you can pass a new class to the indicator and override his style.
Take a look at the link below
https://material-ui.com/api/tabs/#css
To reinforce #Xavier 's answer, I found that we could use the TabIndicatorProps prop for Tabs component as below.
<Tabs
TabIndicatorProps={{
sx: {
top: 0
}
}}
>
<Tab label="One" />
<Tab label="Two" />
<Tab label="Three" />
</Tabs>
2022 Solution
https://mui.com/styles/basics/
#mui/styles is the legacy styling solution for MUI. It depends on JSS as a styling solution, which is not used in the #mui/material anymore, deprecated in v5. If you don't want to have both emotion & JSS in your bundle, please refer to the #mui/system documentation which is the recommended alternative.
⚠️ #mui/styles is not compatible with React.StrictMode or React 18.
You can utilise the sx property on the component to access any css classes directly.
https://mui.com/api/tabs/#css
<Tabs
orientation="vertical"
value={value}
onChange={handleChange}
sx={{
'.MuiTabs-indicator': {
left: 0,
},
}}
>
<Tab label="One" />
<Tab label="Two" />
<Tab label="Three" />
</Tabs>

Resources