How to apply margin between Material-UI Grid items? - reactjs

How can we add margin (empty space) between Material-UI Grid items?
Container's spacing attribute only adds padding on items.
import React from "react";
import ReactDOM from "react-dom";
import { Grid } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles({
root: {
backgroundColor: "red"
},
root2: {
backgroundColor: "green"
}
});
function App() {
const classes = useStyles();
return (
<Grid container spacing={2}>
<Grid item xs={6} className={classes.root}>
hi
</Grid>
<Grid item xs={6} className={classes.root2}>
hi
</Grid>
</Grid>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Change xs attribute so that the total is less than 12 in that row to have some space.
Add margin: "auto" or any other margin as you wish to your items.
import React from "react";
import ReactDOM from "react-dom";
import { Grid } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles({
root: {
backgroundColor: "red",
margin: "auto"
},
root2: {
backgroundColor: "green",
margin: "auto"
}
});
function App() {
const classes = useStyles();
return (
<Grid container spacing={2}>
<Grid item xs={5} className={classes.root}>
hi
</Grid>
<Grid item xs={5} className={classes.root2}>
hi
</Grid>
</Grid>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Related

Grid Errors When Displaying Skills for Portfolio in React

I am currently trying to figure out how to map a Grid for each of my "skills" panels for my Portfolio. The skills are being pulled and iterated over from the arrays you see at the top of the file below, here is my code:
import React from "react";
import { makeStyles} from "#material-ui/core/styles";
import Grid from "#material-ui/core/Grid";
import Paper from "#material-ui/core/Paper";
import styled from 'styled-components';
import typography from '#material-ui/core/Typography';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
color:'green',
alignContent:"center"
},
paper: {
height: 150,
width: 100
},
}));
const frontEnd =['Django','Reactjs','Javascript','HTML','CSS']
const backEnd =['Python','Typescript','Nodejs','Express']
const databases =['MongoDB','MySQL']
const tools = ['AWS','AWS-CDK','Docker','AWS-Lambda','Figma','Microservices','Kubernetes']
const SpacingGrid = (props) => {
// const [spacing] = React.useState(2);
const classes = useStyles();
return (
<div>
<Grid item xs={12}>
<Body align="center">
Front-End
</Body>
{frontEnd.map((skill)=>(
<Body align="center" key={skill}>
{skill}
</Body>
))}
<Paper className={classes.control}>
<Grid container justify="center">
<Grid item>{props.children}</Grid>
<Grid item> </Grid>
</Grid>
</Paper>
</Grid>
))}
</div>
);
};
export default SpacingGrid;
so I am trying to create a separate panel for each of the arrays and give it a title such as "Front-End Skills", "Back-End Skills". Thank you all for your help!

Material-UI Set Class Property From State

I have a component like below. I want to be able to use a value from the state such as [opacity, setOpacity] = useGlobal('opacity') and have the opacity be the value for tileBody background. What would be the best way to go about this?
import React from 'react';
import clsx from 'clsx';
import { makeStyles } from '#material-ui/core/styles';
import Typography from '#material-ui/core/Typography';
import Grid from '#material-ui/core/Grid';
import {CardContent, fade, Hidden} from "#material-ui/core";
import Card from "#material-ui/core/Card";
import { useGlobal, setGlobal, useDispatch } from 'reactn';
/*
options = {
...other options,
tileTransparencyValue: 75,
*/
const useStyles = makeStyles(theme => ({
tile: {
backgroundColor: 'transparent',
},
tileHeader: {
backgroundColor: fade(theme.palette.grey[800], 0.7),
},
tileBody: {
backgroundColor: fade(theme.palette.grey[800], tileTransparencyValue/100),
},
}));
export default function DashTile(props) {
const [options, setOptions] = useGlobal('options');
const {title, content} = props;
const classes = useStyles();
return (
<Grid item lg={4} xs={12}>
<Card className={classes.tile}>
<CardContent className={classes.tileHeader}>
<Typography variant="h5">{title}</Typography>
</CardContent>
<CardContent className={classes.tileBody}>
<Typography variant="content">{content}</Typography>
</CardContent>
</Card>
</Grid>
);
}
You can pass props to your styles like this:
export default function DashTile(props) {
const [options, setOptions] = useGlobal('options');
const [opacity, setOpacity] = useGlobal('opacity')
const {title, content} = props;
const classes = useStyles({opacity})
return (
<Grid item lg={4} xs={12}>
<Card className={classes.tile}>
<CardContent className={classes.tileHeader}>
<Typography variant="h5">{title}</Typography>
</CardContent>
<CardContent className={classes.tileBody}>
<Typography variant="content">{content}</Typography>
</CardContent>
</Card>
</Grid>
);
}
Then you can retrive the props inside the styles like this:
const useStyles = makeStyles(theme => ({
tile: {
backgroundColor: 'transparent',
},
tileHeader: {
backgroundColor: fade(theme.palette.grey[800], 0.7),
},
tileBody: {
backgroundColor: ({opacity}) => fade(theme.palette.grey[800], opacity)
},
}));
Reference: makeStyles

How can I use my custom fontfamilies in my react app

This is my theme.ts file where I created my Muitheme and my fontfamily
import 'typeface-inconsolata'
import 'typeface-quicksand'
import { createMuiTheme, responsiveFontSizes } from '#material-ui/core'
import indigo from '#material-ui/core/colors/indigo'
import yellow from '#material-ui/core/colors/pink'
import red from '#material-ui/core/colors/red'
const theme = createMuiTheme({
typography: {
fontFamily: 'typeface-inconsolata, typeface-quicksand',
fontSize: 17,
fontWeightLight: 300,
fontWeightRegular: 400,
fontWeightMedium: 500,
},
palette: {
primary: indigo,
secondary: red,
error: yellow,
// Used by `getContrastText()` to maximize the contrast between the background and
// the text.
contrastThreshold: 4,
// Used to shift a color's luminance by approximately
// two indexes within its tonal palette.
// E.g., shift from Red 500 to Red 300 or Red 700.
tonalOffset: 0.6,
},
})
export const responsiveTheme = responsiveFontSizes(theme)
This is my App.tsx file where my component is, so I want to change the fonts of the words in the Appbar and in the Grid
import {
AppBar,
Card,
CardHeader,
Container,
createStyles,
Grid,
makeStyles,
Toolbar,
Typography,
} from '#material-ui/core'
import CssBaseline from '#material-ui/core/CssBaseline'
import { ThemeProvider } from '#material-ui/styles'
import React, { FC } from 'react'
import logo from '../icons/logo.svg'
import { responsiveTheme } from '../theme'
const useStyles = makeStyles(theme =>
createStyles({
main: {
height: '90vh',
background: `url(${logo}) no-repeat center / 200px`,
marginTop: theme.spacing(10),
},
})
)
const App: FC = () => {
const classes = useStyles()
return (
<ThemeProvider theme={responsiveTheme}>
<CssBaseline />
<Container maxWidth="lg">
<AppBar color="secondary" position="fixed">
<Toolbar>
<Typography variant="h6" noWrap>
Projektvorlage
</Typography>
</Toolbar>
</AppBar>
<div className={classes.main}>
<Grid container spacing={2} justify="center">
{['Pfannkuchen', 'Pizza', 'Salat', 'Nudeln mit Tomatensauce'].map(
recipe => (
<Grid key={recipe} item xs={12} md={6} lg={4}>
<Card>
<CardHeader title={recipe} />
</Card>
</Grid>
)
)}
</Grid>
</div>
</Container>
</ThemeProvider>
)
}
export default App
So basically I want to change the fonts of the texts but I dont know how to use my fontfamily. There are "variants" but I don't understand what they mean exactly, Im new to react/typescript.
If you want to continue introducing styles via Material-UI, what I would do is create myself in the parent that wraps all the global styles, like the following ones:
globalStyles.styles.tsx
import { createStyles } from "#material-ui/core/styles";
export const globalStyles = (theme: Theme) => createStyles({
"#global": {
body: {
maxHeight: "100vh",
margin: 0,
fontFamily:
},
"#root": {
maxHeight: "100vh",
},
});
app.component.tsx
const AppInner: React.FC<AppProps> = props => { ... };
const App = withStyles(globalStyles)(AppInner);
PD: App component must be inside of <ThemeProvider theme={responsiveTheme}>...</ThemeProvider>

How can I set an static outlined div similar to Material-UI's outlined textfield?

I want wrap some TextFields in a outlined container and I found this answer. This work as i want:
But when I click in an inside textfield all the texfields focused:
This is my code:
import React from "react";
import ReactDOM from "react-dom";
import OutlinedDiv from "./OutlinedDiv";
import TextField from "#material-ui/core/TextField";
import Grid from "#material-ui/core/Grid";
function App() {
return (
<div className="App">
<OutlinedDiv label="DIV">
<Grid container justify="center" alignItems="center" spacing={3}>
<Grid item sm={4} xs={12}>
<TextField label="Text1" variant="outlined" />
</Grid>
<Grid item sm={4} xs={12}>
<TextField label="Text2" variant="outlined" />
</Grid>
<Grid item sm={4} xs={12}>
<TextField label="Text3" variant="outlined" />
</Grid>
<Grid item sm={4} xs={12}>
<TextField label="Text4" variant="outlined" />
</Grid>
<Grid item sm={4} xs={12}>
<TextField label="Text5" variant="outlined" />
</Grid>
<Grid item sm={4} xs={12}>
<TextField label="Text6" variant="outlined" />
</Grid>
</Grid>
</OutlinedDiv>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
How I can achive this style and when click in an inside component only focus the selected component?
A response with another approach and the similar solution for outlined div is welcome.
Thanks in advance.
Below is an approach that does not leverage TextField or FormControl and thus can be safely used to wrap other inputs. This copies some styles from OutlinedInput and the InputLabel styles applied when within a FormControl.
import React from "react";
import ReactDOM from "react-dom";
import InputLabel from "#material-ui/core/InputLabel";
import NotchedOutline from "#material-ui/core/OutlinedInput/NotchedOutline";
import { withStyles } from "#material-ui/core/styles";
import clsx from "clsx";
const styles = {
root: {
position: "relative",
marginTop: "8px"
},
contentWrapper: {
position: "relative"
},
content: {
padding: "18.5px 14px"
},
inputLabel: {
position: "absolute",
left: 0,
top: 0,
// slight alteration to spec spacing to match visual spec result
transform: "translate(0, 24px) scale(1)"
},
notchedOutline: {}
};
const LabelledOutline = ({ classes, id, label, children, className }) => {
const [labelWidth, setLabelWidth] = React.useState(0);
const labelRef = React.useRef(null);
React.useEffect(() => {
const labelNode = ReactDOM.findDOMNode(labelRef.current);
setLabelWidth(labelNode != null ? labelNode.offsetWidth : 0);
}, [label]);
return (
<div className={clsx(className, classes.root)}>
<InputLabel
ref={labelRef}
htmlFor={id}
variant="outlined"
className={classes.inputLabel}
shrink
>
{label}
</InputLabel>
<div className={classes.contentWrapper}>
<div id={id} className={classes.content}>
{children}
<NotchedOutline
className={classes.notchedOutline}
notched
labelWidth={labelWidth}
/>
</div>
</div>
</div>
);
};
export default withStyles(styles)(LabelledOutline);
And below is an example using it both without customization and once with customized colors for the label, outline, and content that changes on hover.
import React from "react";
import ReactDOM from "react-dom";
import { withStyles } from "#material-ui/core/styles";
import LabelledOutline from "./LabelledOutline";
const CustomColorLabelledOutline = withStyles({
root: {
"& $notchedOutline": {
borderColor: "purple"
},
"&:hover $notchedOutline": {
borderColor: "orange"
},
"& $inputLabel": {
color: "green"
},
"&:hover $inputLabel": {
color: "blue"
},
"& $content": {
color: "black"
},
"&:hover $content": {
color: "purple"
}
},
notchedOutline: {},
inputLabel: {},
content: {}
})(LabelledOutline);
function App() {
return (
<div>
<LabelledOutline id="myID" label="My Label">
My Content
</LabelledOutline>
<CustomColorLabelledOutline label="My Label">
My Content with custom label and outline color
</CustomColorLabelledOutline>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
And the obligatory TS version (deeply inspired by #Ryan Cogswell's version):
import React, { ReactElement, ReactNode } from "react";
import InputLabel from "#material-ui/core/InputLabel";
import NotchedOutline from "#material-ui/core/OutlinedInput/NotchedOutline";
import { makeStyles, Theme } from "#material-ui/core/styles";
import clsx from "clsx";
const useStyles = makeStyles((theme: Theme) => ({
root: {
position: "relative",
marginTop: "8px",
},
contentWrapper: {
position: "relative",
},
content: {
// padding: "18.5px 14px",
padding: theme.spacing(1),
},
inputLabel: {
position: "absolute",
left: 0,
top: 0,
// slight alteration to spec spacing to match visual spec result
transform: "translate(0, 24px) scale(1)",
},
notchedOutline: { borderRadius: theme.shape.borderRadius },
}));
interface Props {
id: string;
label: string;
children: ReactNode;
className?: string;
}
export default function Conftainer({ id, label, children, className }: Props): ReactElement {
const [labelWidth, setLabelWidth] = React.useState(0);
const labelRef = React.useRef(null);
React.useEffect(() => {
if (labelRef && labelRef.current && (labelRef.current as any).offsetWidth) {
setLabelWidth((labelRef.current as any).offsetWidth);
}
}, [label]);
const classes = useStyles();
return (
<div className={clsx(className, classes.root)}>
<InputLabel
ref={labelRef}
htmlFor={id}
variant="outlined"
className={classes.inputLabel}
shrink
>
{label}
</InputLabel>
<div className={classes.contentWrapper}>
<div id={id} className={classes.content}>
{children}
<NotchedOutline className={classes.notchedOutline} notched labelWidth={labelWidth} />
</div>
</div>
</div>
);
}
(any edits to get rid of the any more than welcome)
I don't have enough point to post a comment on #AntonOfTheWoods answer (I signed up SO today especially for this question).
Just use const labelRef = React.useRef<HTMLLabelElement>(null); and you should be able to get rid of the any

React Material UI Grid

Is there any correct and easy way to create kind of table with Material UI ?. direction="column" or direction="row" are not working if I want to have different height columns. Any suggestions?
If you want to use Material-ui built-in Grid system you can do it by using 2 grid containers, one with direction="row" (default) and second (child) with direction="column".
It needs a bit of individual styling, might look "hacky", but I don't know other way:
import React from "react";
import ReactDOM from "react-dom";
import Grid from "#material-ui/core/Grid";
import Box from "#material-ui/core/Box";
import { makeStyles } from "#material-ui/styles";
const useStyles = makeStyles({
box: {
height: "100%",
width: "100%"
},
container: {
height: "400px"
},
innerContainer: {
height: "100%"
},
item: {
flex: 1
}
});
function App() {
const classes = useStyles();
return (
<Grid spacing={4} className={classes.container} container>
<Grid xs={4} item>
<Grid
spacing={4}
direction="column"
className={classes.container}
container
>
<Grid className={classes.item} item>
<Box className={classes.box} bgcolor="blue" />
</Grid>
<Grid className={classes.item} item>
<Box className={classes.box} bgcolor="red" />
</Grid>
</Grid>
</Grid>
<Grid xs={8} item>
<Box className={classes.box} bgcolor="green" />
</Grid>
</Grid>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
LIVE EXAMPlE
Other option is to use CSS Grid. It requires much less elements, and (at least for me) is simplier. However, it doesn't work in Internet Explorer, if you care about such thing.
import React from "react";
import ReactDOM from "react-dom";
import Box from "#material-ui/core/Box";
import { makeStyles } from "#material-ui/styles";
const useStyles = makeStyles({
container: {
height: '400px',
width: "100%",
display: 'grid',
gridTemplateColumns: '1fr 2fr',
gridTemplateRows: '1fr 1fr',
gridGap: "20px",
},
firstChild: {
gridRow: '1 / 2',
gridColumn: '1 / 2',
},
secondChild: {
gridRow: '1 / 3',
gridColumn: '2 / 3',
},
thirdChild: {
gridRow: '2 / 3',
gridColumn: '1 / 2',
},
});
function App() {
const classes = useStyles();
return (
<Box className={classes.container}>
<Box className={classes.firstChild} bgcolor="blue" />
<Box className={classes.secondChild} bgcolor="red" />
<Box className={classes.secondThird} bgcolor="green" />
</Box>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
LIVE EXAMPLE

Resources