Skip to content

Material-ui by internat

April 14, 2023 | 12:00 AM

Material ui

Table of Contents

Open Table of Contents

Form- react-hook-form

import React from 'react';
import { useForm, RegisterOptions } from 'react-hook-form';
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';

interface FormData {
  name: string;
  email: string;
  password: string;
  message: string;
}

const MyForm: React.FC = () => {
  const {
    register, // Register function from react-hook-form
    handleSubmit, // Submit handler from react-hook-form
    formState: { errors }, // Errors object from react-hook-form
  } = useForm<FormData>(); // Initialize useForm hook with FormData type as generic

  const onSubmit = (data: FormData) => {
    // Handle form submission
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* Name field */}
      <TextField
        label="Name"
        variant="outlined"
        {...register('name', {
          required: 'This field is required',
        } as RegisterOptions)}
        error={!!errors.name} // Check if errors exist for 'name' field
        helperText={errors.name?.message} // Display error message for 'name' field
      />

      {/* Email field */}
      <TextField
        label="Email"
        variant="outlined"
        {...register('email', {
          required: 'This field is required',
          pattern: {
            value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
            message: 'Invalid email address',
          },
        } as RegisterOptions)}
        error={!!errors.email} // Check if errors exist for 'email' field
        helperText={errors.email?.message} // Display error message for 'email' field
      />

      {/* Password field */}
      <TextField
        label="Password"
        variant="outlined"
        type="password" // Set input type to password
        {...register('password', {
          required: 'This field is required',
        } as RegisterOptions)}
        error={!!errors.password} // Check if errors exist for 'password' field
        helperText={errors.password?.message} // Display error message for 'password' field
      />

      {/* Message textarea field */}
      <TextField
        label="Message"
        variant="outlined"
        multiline // Set multiline prop to true for textarea
        rows={4} // Set number of rows for textarea
        {...register('message', {
          required: 'This field is required',
        } as RegisterOptions)}
        error={!!errors.message} // Check if errors exist for 'message' field
        helperText={errors.message?.message} // Display error message for 'message' field
      />

      {/* Submit button */}
      <Button type="submit" variant="contained" color="primary">
        Submit
      </Button>
    </form>
  );
};

export default MyForm;

React- form with checkbox

import React from 'react';
import { useForm, RegisterOptions } from 'react-hook-form';
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import FormHelperText from '@mui/material/FormHelperText'; // Add import for FormHelperText

interface FormData {
  name: string;
  email: string;
  password: string;
  message: string;
  acceptTerms: boolean;
}

const MyForm: React.FC = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormData>();

  const onSubmit = (data: FormData) => {
    // Handle form submission
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* Name field */}
      <TextField
        label="Name"
        variant="outlined"
        {...register('name', {
          required: 'This field is required',
        } as RegisterOptions)}
        error={!!errors.name}
        helperText={errors.name?.message}
      />

      {/* Email field */}
      <TextField
        label="Email"
        variant="outlined"
        {...register('email', {
          required: 'This field is required',
          pattern: {
            value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
            message: 'Invalid email address',
          },
        } as RegisterOptions)}
        error={!!errors.email}
        helperText={errors.email?.message}
      />

      {/* Password field */}
      <TextField
        label="Password"
        variant="outlined"
        type="password"
        {...register('password', {
          required: 'This field is required',
        } as RegisterOptions)}
        error={!!errors.password}
        helperText={errors.password?.message}
      />

      {/* Message textarea field */}
      <TextField
        label="Message"
        variant="outlined"
        multiline
        rows={4}
        {...register('message', {
          required: 'This field is required',
        } as RegisterOptions)}
        error={!!errors.message}
        helperText={errors.message?.message}
      />

      {/* Checkbox field */}
      <FormControlLabel
        control={
          <Checkbox
            {...register('acceptTerms', {
              required: 'You must accept the terms and conditions',
            } as RegisterOptions)}
            color="primary"
          />
        }
        label="I accept the terms and conditions"
      />

      {/* Error message for checkbox */}
      {errors.acceptTerms && (
        <FormHelperText error>{errors.acceptTerms.message}</FormHelperText>
      )}

      {/* Submit button */}
      <Button type="submit" variant="contained" color="primary">
        Submit
      </Button>
    </form>
  );
};

export default MyForm;

React- form with checkbox and dropdown

Error msg in drop down doesnot go away in first attempt

import React from 'react';
import { useForm, RegisterOptions } from 'react-hook-form';
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import FormHelperText from '@mui/material/FormHelperText'; // Add import for FormHelperText
import Box from '@mui/material/Box';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import InputLabel from '@mui/material/InputLabel';
import Select from '@mui/material/Select';

interface FormData {
    name: string;
    email: string;
    password: string;
    message: string;
    acceptTerms: boolean;
    country: string;
}

const MyForm: React.FC = () => {
    const {
        register,
        handleSubmit,
        formState: { errors },
    } = useForm<FormData>();

    const onSubmit = (data: FormData) => {
        console.log(data);
    };

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <Box sx={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
                {/* Name field */}
                <TextField
                    label="Name"
                    variant="outlined"
                    {...register('name', {
                        required: 'This field is required',
                    } as RegisterOptions)}
                    error={!!errors.name}
                    helperText={errors.name?.message}
                />

                {/* Email field */}
                <TextField
                    label="Email"
                    variant="outlined"
                    {...register('email', {
                        required: 'This field is required',
                        pattern: {
                            value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
                            message: 'Invalid email address',
                        },
                    } as RegisterOptions)}
                    error={!!errors.email}
                    helperText={errors.email?.message}
                />

                {/* Password field */}
                <TextField
                    label="Password"
                    variant="outlined"
                    type="password"
                    {...register('password', {
                        required: 'This field is required',
                    } as RegisterOptions)}
                    error={!!errors.password}
                    helperText={errors.password?.message}
                />

                {/* Message textarea field */}
                <TextField
                    label="Message"
                    variant="outlined"
                    multiline
                    rows={4}
                    {...register('message', {
                        required: 'This field is required',
                    } as RegisterOptions)}
                    error={!!errors.message}
                    helperText={errors.message?.message}
                />
                {/* Country dropdown field */}
                <FormControl variant="outlined" fullWidth error={Boolean(errors.country)}>
                    <InputLabel htmlFor="country-label">Country</InputLabel>
                    <Select
                        labelId="country-label"
                        label="Country"
                        {...register('country', { required: 'This field is required' })}
                    >
                        <MenuItem value="USA">USA</MenuItem>
                        <MenuItem value="Canada">Canada</MenuItem>
                        <MenuItem value="UK">UK</MenuItem>
                        <MenuItem value="Australia">Australia</MenuItem>
                    </Select>
                    {errors.country && (
                        <FormHelperText error>{errors.country.message}</FormHelperText>
                    )}
                </FormControl>
                {/* Checkbox field */}
                <FormControlLabel
                    control={
                        <Checkbox
                            {...register('acceptTerms', {
                                required: 'You must accept the terms and conditions',
                            } as RegisterOptions)}
                            color="primary"
                        />
                    }
                    label="I accept the terms and conditions"
                />

                {/* Error message for checkbox */}
                {errors.acceptTerms && (
                    <FormHelperText error>{errors.acceptTerms.message}</FormHelperText>
                )}

                {/* Submit button */}
                <Button type="submit" variant="contained" color="primary">
                    Submit
                </Button>
            </Box>
        </form>
    );
};

export default MyForm;

Header.tsx

import {
  AppBar,
  Box,
  Button,
  Divider,
  Drawer,
  IconButton,
  SxProps,
  Toolbar,
  Typography,
} from "@mui/material";
import { Fastfood, Menu } from "@mui/icons-material";
import { NavLink } from "react-router-dom";
import { useState } from "react";

function Header() {
  const [openDrawer, setOpenDrawer] = useState(false);

  return (
    <Box>
      <AppBar component={"nav"} sx={{ bgcolor: "black" }}>
        <Toolbar>
          {/* hambergan icon */}
          <IconButton
            color="inherit" // it stops animating if color is not provided
            aria-label={"open-drawer"}
            edge="start"
            sx={styles.icon}
            onClick={() => setOpenDrawer(pre => !pre)}
          >
            <Menu sx={{ color: "goldenrod" }} />
          </IconButton>
          {/* Nav heading and icon */}
          <Typography
            color={"goldenrod"}
            variant="h6"
            component={"div"}
            sx={{ flexGrow: 1 }}
          >
            <Fastfood /> My Restaurant
          </Typography>
          <Box sx={styles.navLinkContainer}>
            {/* navlinks */}
            <NavbarWrapper onclick={() => {}} />
          </Box>
        </Toolbar>
      </AppBar>
      <Drawer
        variant="temporary"
        open={openDrawer}
        onClose={() => setOpenDrawer(pre => !pre)}
        sx={styles.mobileNavLinkContainer}
      >
        <Typography variant="h5" sx={{ textAlign: "center", margin: 1 }}>
          Menu
        </Typography>
        <Divider></Divider>
        <NavbarWrapper onclick={() => setOpenDrawer(pre => !pre)} />
      </Drawer>
      <Box>
        <Toolbar /> {/* works as a spacer  */}
      </Box>
    </Box>
  );
}

export default Header;

function NavbarWrapper({ onclick }: { onclick: () => void }) {
  return (
    <>
      <Button
        component={NavLink} // NavLink adds an active class to the component which can be targeted in css
        to="/"
        onClick={onclick}
      >
        Home
      </Button>
      <Button component={NavLink} to="/menu" onClick={onclick}>
        Menu
      </Button>
      <Button component={NavLink} to="/about" onClick={onclick}>
        About
      </Button>
      <Button component={NavLink} to="/contact" onClick={onclick}>
        Contact
      </Button>
    </>
  );
}

type StylesProps = {
  [key: string]: SxProps;
};
const styles: StylesProps = {
  navLinkContainer: {
    display: { xs: "none", sm: "flex" },
    gap: 5,
    listStyle: "none",
    textDecoration: "none",
    "& a": {
      color: "goldenrod",
    },
    "& a.active": {
      color: "blueviolet",
    },
  },
  mobileNavLinkContainer: {
    display: { xs: "block", sm: "none" },
    "& .MuiDrawer-paper": {
      boxSizing: "border-box",
      width: "200px",
      "& a": {
        color: "goldenrod",
      },
      "& a.active": {
        color: "blueviolet",
      },
    },
  },
  icon: {
    mr: 2,
    display: { sm: "none" },
  },
};

Theme

Setup src/App.tsx

//...other imports
import { CssBaseline, SxProps, ThemeProvider } from "@mui/material";
import theme from "./lib/theme";
function App() {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      {/* other stuff here */}
    </ThemeProvider>
  );
}

src/lib/theme.ts - there are certain limitation to where customColors will work so check before use

import { createTheme } from "@mui/material";
import { green, grey, indigo } from "@mui/material/colors";

declare module "@mui/material/styles" {
  interface Palette {
    customNeutral: {
      light: string;
      medium: string;
      normal: string;
      main: string;
    };
    customGreen: Palette["primary"];
  }

  interface PaletteOptions {
    customNeutral?: {
      light: string;
      medium: string;
      normal: string;
      main: string;
    };
    customGreen?: PaletteOptions["primary"];
  }
}

declare module "@mui/material/styles" {
  interface TypographyVariants {
    link: React.CSSProperties;
    cardTitle: React.CSSProperties;
    h6: React.CSSProperties;
    h7: React.CSSProperties;
    h8: React.CSSProperties;
  }

  interface TypographyVariantsOptions {
    link?: React.CSSProperties;
    cardTitle?: React.CSSProperties;
    h6?: React.CSSProperties;
    h7?: React.CSSProperties;
    h8?: React.CSSProperties;
  }
}

declare module "@mui/material/Typography" {
  interface TypographyPropsVariantOverrides {
    link: true;
    cardTitle: true;
    h6: true;
    h7: true;
    h8: true;
  }
}

let theme = createTheme({
  palette: {
    primary: {
      main: indigo[500],
      light: indigo["A700"],
    },
    secondary: {
      main: indigo[50],
    },
    customNeutral: {
      light: grey[50],
      medium: grey[200],
      normal: grey[700],
      main: grey[900],
    },
    customGreen: {
      main: green[800],
    },
  },
});

theme = createTheme(theme, {
  typography: {
    link: {
      fontSize: "0.8rem",
      fontWeight: 500,
      color: theme.palette.primary.main,
      display: "block",
      cursor: "pointer",
      [theme.breakpoints.up("md")]: {
        fontSize: "0.9rem",
      },
    },
    cardTitle: {
      fontSize: "1.2rem",
      display: "block",
      fontWeight: 500,
    },
    h6: {
      fontSize: "1rem",
    },
    h7: {
      fontSize: "0.8rem",
    },
    h8: {
      fontSize: "0.7rem",
    },
  },
});

export default theme;