Skip to content

brandonscript/mui-flexy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

flex-logo

mui-flexy

A flexbox wrapper for Material UI Box and Grid components with handy shorthand props.

NPM Version NPM Downloads GitHub Issues or Pull Requests MUI Versions React Versions

Why?

The problem

If you have gotten confused whether to use justify-content or align-items, then mui-flexy is for you! Vanilla CSS requires a lot of mental gymnastics to remember which alignment property to use depending on the axis of your flexbox:

justify-content aligns along the main axis and align-items aligns along the cross axis. When you change the axis, you have to re-write your alignments. This gets exponentially more difficult when you introduce responsive breakpoints.

The solution

Science and math solved this problem a long time ago with constants like x and y to represent 2-dimensional space, where x is the horizontal axis and y is the vertical axis.

mui-flexy gives you a way to align things in the same way using x and y props instead, calculating all the hard CSS stuff for you so you don't have to.

Instead of:

<FlexBox
  justifyContent="center" // is this the main or cross axis?
  alignItems="center" // maybe I can use stretch or space-around? 🤷‍♂️
  flexDirection="row" // if I change this to column, do I need to change the other two?
  width="100vw"
  height="100vh"
/>

You can just do:

<FlexBox x="center" y="center" width="100vw" height="100vh" />

// and

<FlexBox column x="left" y="bottom" />

// and

<FlexBox column x="center" y="stretch" />

The real power of mui-flexy comes from its ability to handle the switch between different orientations at different breakpoints.

You can write this:

<FlexBox x={{ xs: "left", lg: "right" }} y="center" row={{ xs: true, md: false }} />

...instead of this:

<Box
  sx={{
    display: "flex",
    justifyContent: { xs: "flex-start", md: "center" },
    alignItems: { xs: "center", md: "flex-start", lg: "flex-end" },
    flexDirection: { xs: "row", md: "column" },
  }}
/>

Interactive demo & docs

Check out the live demo for interactive examples of all mui-flexy's features:

mui-flexy

Get started

(Note: Breaking changes in v2.0.0)

mui-flexy is now a monorepo with separate packages for each MUI version (@mui-flexy/v5, @mui-flexy/v6, @mui-flexy/v7) with a dedicated @mui-flexy/core package for shared utilities. Each package is now optimized specifically for its MUI version, resulting in smaller bundle sizes and better TypeScript resolution.

Make sure to update your imports to the new package structure:

import { FlexBox } from "mui-flexy"; // old
import { FlexBox } from "@mui-flexy/v7"; // new

And, as of v1.2.0, CommonJS is no longer supported. If you need it, please use an older version, or file a bug/PR.

Installing

Choose the package that matches your MUI version:

# For @mui/material v7
npm install @mui-flexy/v7

# For @mui/material v6
npm install @mui-flexy/v6

# For @mui/material v5
npm install @mui-flexy/v5

# or...
yarn add @mui-flexy/v{5,6,7}
pnpm add @mui-flexy/v{5,6,7}

Dependencies & setup

Make sure you have @mui/material and its dependencies installed, as well as React:

yarn add @mui/material @emotion/react @emotion/styled react react-dom
# or
npm install @mui/material @emotion/react @emotion/styled react react-dom

If you haven't already, make sure to wrap your app with the MUI ThemeProvider:

import { ThemeProvider, createTheme } from "@mui/material/styles";
import { CssBaseline } from "@mui/material";

const theme = createTheme({
  palette: {
    mode: "light", // or "dark"
  },
});
const App = () => (
  <ThemeProvider theme={theme}>
    <CssBaseline />
    <YourApp />
  </ThemeProvider>
);

If you are using a SSR-based framework like Next.js, you should use an Emotion cache to avoid hydration errors:

import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";

const cache = createCache({ key: "my-app-css" });

const App = () => (
  <CacheProvider value={cache}>
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <YourApp />
    </ThemeProvider>
  </CacheProvider>
);

Using mui-flexy

FlexBox: The basics / tl;dr

mui-flexy is a drop-in replacement for MUI's Box and Grid components, with the added benefit of x and y props for alignment.

Import the FlexBox or FlexGrid components from the appropriate version package and use them in your app as you would with MUI's Box or Grid components:

import { Typography } from "@mui/material"; // or use a <p> if you don't like fun typography

// For MUI v5
import { FlexBox, FlexGrid } from "@mui-flexy/v5";

// For MUI v6
import { FlexBox, FlexGrid } from "@mui-flexy/v6";

// For MUI v7
import { FlexBox, FlexGrid } from "@mui-flexy/v7";

<FlexBox x="top" y="center">
  <Typography>Hello, Bajor</Typography>
</FlexBox>;

(To do this without mui-flexy, you'd need to do one of these)

// Use sx:
<Box sx={{ display: "flex", justifyContent: "center", alignItems: "center" }}>
  <Typography>Hello, Bajor</Typography>
</Box>;

// Use a styled component (to prevent re-creating the flexbox styles for every instance):
const CenteredFlexBox = styled(Box)({
  display: "flex",
  justifyContent: "center",
  alignItems: "center",
});

<CenteredFlexBox>
  <Typography>Hello, Bajor</Typography>
</CenteredFlexBox>;

FlexGrid

FlexGrid (or FlexGrid2 for MUI v6) supports all the grid-alignment props alongside the x and y props for alignment:

// For MUI v5 (uses Grid)
import { FlexBox, FlexGrid } from "@mui-flexy/v5";

// For MUI v6 (uses Grid2)
import { FlexBox, FlexGrid2 } from "@mui-flexy/v6";

// For MUI v7 (uses Grid)
import { FlexBox, FlexGrid } from "@mui-flexy/v7";

// Usage is the same across versions:
<FlexGrid2 container x="center" y="top">
  <FlexGrid2 item size={{ xs: 12, sm: 6, md: 4, lg: 3 }} x="center" y="center">
    <Typography>Grids are cool</Typography>
  </FlexGrid2>
</FlexGrid2>;

(Note: the syntax for legacy Grid is slightly different)

// For MUI v5
import { FlexBox, FlexGrid } from "@mui-flexy/v5";

<FlexGrid container x="center" y="center">
  <FlexGrid item xs={12} sm={6} md={4} lg={3}>
    <Typography>Grids are cool</Typography>
  </FlexGrid>
</FlexGrid>;

More examples & responsive usage

The row and column props are used to switch between the different orientations of the flexbox container.

<FlexBox x="center" y="center" row />

// ...is equivalent to:

<Box sx={{
  display: "flex",
  justifyContent: "center",
  alignItems: "center",
  flexDirection: "row"
}} />

It used to get tricky when you switch the flex-direction:

<>
  <FlexBox x="left" y="bottom" row />
  <FlexBox x="left" y="bottom" column />
</>

// ...is equivalent to:
<>
  <Box sx={{
    display: "flex",
    justifyContent: "flex-start",
    alignItems: "flex-end",
    flexDirection: "row"
  }} />
  <Box sx={{
    display: "flex",
    justifyContent: "flex-end",
    alignItems: "flex-start",
    flexDirection: "column"
  }} />
</>

FlexBox and FlexGrid also support ResponsiveStyleObject array notation:

<FlexBox x={["left", "center", "right"]} y={["bottom", "center", "top"]} row />

// ...is equivalent to:

<Box sx={{
  display: "flex",
  justifyContent: ["flex-start", "center", "flex-end"],
  alignItems: ["flex-end", "center", "flex-start"],
  flexDirection: "row"
}} />
<FlexBox x={["left", "space-between"]} y={["top", "center"]} flexDirection={["row", "column"]} />

// ...is equivalent to:

<Box sx={{
  display: "flex",
  justifyContent: ["flex-start", "center"],
  alignItems: ["flex-start", "space-between"],
  flexDirection: ["row", "column"]
}} />

...and ResponsiveStyleObject object notation:

<FlexBox
  x={{ xs: "left", sm: "center", md: "right" }}
  y={{ xs: "bottom", sm: "center", md: "top" }}
/>

// ...is equivalent to:

<Box sx={{
  display: "flex",
  justifyContent: { xs: "flex-start", sm: "center", md: "flex-end" },
  alignItems: { xs: "flex-end", sm: "center", md: "flex-start" },
  flexDirection: "row"
}} />

And remember, mui-flexy helps you handle the complex switch between row and column at different breakpoints:

<FlexBox
  x={{ xs: "left", lg: "right" }}
  y="center"
  row={{ xs: true, md: false }}
/>

// ...is equivalent to:

<Box sx={{
  display: "flex",
  justifyContent: { xs: "flex-start", md: "center" },
  alignItems: { xs: "center", md: "flex-start", lg: "flex-end" },
  flexDirection: { xs: "row", md: "column" }
}} />

...and:

<FlexBox x="left" y="bottom" row={{ xs: true, md: false }} />

// ...is equivalent to:

<Box sx={{
  justifyContent: {
    xs: "flex-start",
    md: "flex-end"
  },
  alignItems: {
    xs: "flex-end",
    md: "flex-start"
  },
  flexDirection: { xs: "row", md: "column" }
}} />

You can mix and match arrays and objects for x, y, row, and column properties. Notice how complicated this gets when we mix and match breakpoints:

<FlexBox x="center" y={["center", "stretch"]} row={{ xs: true, md: false }} />

// ...is equivalent to:

<Box sx={{
  justifyContent: { xs: "center", md: "stretch" },
  alignItems: { xs: "center", sm: "stretch", md: "center" },
  flexDirection: { xs: "row", md: "column" }
}} />

It supports reverse and flex-wrap too:

<FlexBox x="left" y="center" reverse row />

// ...is equivalent to:

<Box sx={{
  display: "flex",
  justifyContent: "flex-start",
  alignItems: "center",
  flexDirection: "row-reverse"
}} />
<FlexBox x="left" y="center" flexWrap="nowrap" />

// ...is equivalent to:

<Box sx={{
  display: "flex",
  justifyContent: "flex-start",
  alignItems: "center",
  flexDirection: "row",
  flexWrap: "nowrap"
}} />

FlexGrid migration and legacy Grid support

MUI v5 introduced Unstable_Grid2, a new grid system based on flexbox. In v6, Unstable_Grid2 has been renamed to Grid2, and Grid is deprecated. In v7, Grid2 has replaced the flagship Grid component.

// FlexGrid (v5), based on @mui/material/Grid
<FlexGrid container x="center" y="center">
  <FlexGrid item xs={12} sm={6} md={4} lg={3}>
    <Typography>Grids are cool</Typography>
  </FlexGrid>
</FlexGrid>

// FlexGrid2 (v6), based on @mui/material/Grid2
<FlexGrid2 container x="center" y="center">
  <FlexGrid2 size={{ xs: 12, sm: 6, md: 4, lg: 3 }}>
    <Typography>Grids are cool</Typography>
  </FlexGrid2>
</FlexGrid2>

// FlexGrid (v7+), based on @mui/material/Grid
<FlexGrid container x="center" y="center">
  <FlexGrid size={{ xs: 12, sm: 6, md: 4, lg: 3 }}>
    <Typography>Grids are cool</Typography>
  </FlexGrid>
</FlexGrid>

Refs & component overrides

Both FlexBox and FlexGrid are wrapped with forwardRef, so you can pass a ref to FlexBox and FlexGrid. You can also pass a component prop to override the default div:

import { forwardRef } from "react";

const boxRef = useRef(null);

<FlexBox ref={boxRef} id="my-flex-box">
  <Typography>{`I'm a FlexBox with id ${boxRef.current?.id}`}</Typography>
</FlexBox>;
const SpanFlex = <FlexBox component="span" x="center" y="center" />;
const TypographyFlex = <FlexBox component={Typography} x="center" y="center" variant="subtitle1" />;

styled() support

mui-flexy supports the styled() function from @mui/material/styles to create styled components:

const CenterCenterBox = styled(FlexBox)({
  display: "flex",
  justifyContent: "center",
  alignItems: "center",
});

It supports all of the advanced functions available through styled() for theme-injection, prop-passing, and TypeScript:

shouldForwardProp:
const CountBox =
  styled(FlexBox, {
    shouldForwardProp: (prop) => !["count"].includes(String(prop)),
  }) <
  { count: number } >
  (({ theme, count }) =>
    theme.unstable_sx({
      color: (theme) => (count > 8 ? theme.palette.primary.warning : theme.palette.primary.main),
    }));
inline components:
const ResetBox = styled(
  ({ resetFn, ...props }: FlexBoxProps & { resetFn?: () => void }) => <FlexBox x="center" y="center" {...props} onClick={resetFn} />,
)(({ theme }) => ({
  maxWidth: 100,
  maxHeight: 100,
}));
theme.unstable_sx:
const SquircleishBox = styled(FlexBox)(({ theme }) =>
  theme.unstable_sx({
    backgroundColor: theme.palette.primary.light,
    borderRadius: 2, // use theme.unstable_sx to use theme values
    px: 1, // use theme.unstable_sx to use theme values
  }),
);

About

A flexbox wrapper for MaterialUI Box and Grid components with handy shorthand props

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published