Skip to main content
Sync UI provides multiple grid layout variants to beautifully organize your content with smooth animations.

Installation

Grids in Sync UI are built using Material-UI and Framer Motion:
npm install @mui/material @emotion/react @emotion/styled framer-motion

Variants

Masonry

A cascading grid layout with items of varying heights.
import React from "react";
import { Box } from "@mui/material";
import { motion } from "motion/react";

const MotionBox = motion.create(Box);

const MasonryGrid = () => {
  const images = [
    "https://images.unsplash.com/photo-1506905925346-21bda4d32df4",
    "https://images.unsplash.com/photo-1507525428034-b723cf961d3e",
    "https://images.unsplash.com/photo-1441974231531-c6227db76b6e",
    "https://images.unsplash.com/photo-1469474968028-56623f02e42e",
  ];

  const items = Array.from({ length: 9 }, (_, i) => ({
    id: i + 1,
    imageUrl: images[i % images.length],
  }));

  return (
    <MotionBox
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      sx={{
        columnCount: { xs: 1, sm: 2, md: 3 },
        columnGap: "16px",
        padding: 2,
        width: "100%",
      }}
    >
      {items.map((item, index) => (
        <MotionBox
          key={item.id}
          whileHover={{ scale: 1.03 }}
          sx={{
            mb: "16px",
            breakInside: "avoid-column",
            borderRadius: 2,
            overflow: "hidden",
            cursor: "pointer",
            boxShadow: "0 2px 10px rgba(0,0,0,0.1)",
          }}
        >
          <Box
            sx={{
              width: "100%",
              height: 250 + (index % 4) * 40,
              backgroundImage: `url(${item.imageUrl})`,
              backgroundSize: "cover",
              backgroundPosition: "center",
            }}
          />
        </MotionBox>
      ))}
    </MotionBox>
  );
};

export default MasonryGrid;

Bento

A Japanese-style compartmentalized grid with structured layout.
import React from "react";
import { Box } from "@mui/material";
import { motion } from "motion/react";

const MotionBox = motion.create(Box);

const BentoGrid = () => {
  const images = [
    "https://images.unsplash.com/photo-1506905925346-21bda4d32df4",
    "https://images.unsplash.com/photo-1507525428034-b723cf961d3e",
    "https://images.unsplash.com/photo-1441974231531-c6227db76b6e",
    "https://images.unsplash.com/photo-1469474968028-56623f02e42e",
    "https://images.unsplash.com/photo-1439066615861-d1af74d74000",
  ];

  return (
    <MotionBox
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      sx={{
        padding: 2,
        display: "grid",
        gap: 2,
        gridTemplateColumns: { xs: "1fr", md: "2fr 1fr" },
        gridTemplateRows: "auto auto auto",
      }}
    >
      <MotionBox
        sx={{
          gridColumn: { md: "1" },
          gridRow: { md: "1 / 3" },
          minHeight: { xs: 260, md: 480 },
          backgroundImage: `url(${images[0]})`,
          backgroundSize: "cover",
          borderRadius: 3,
          boxShadow: "0 0 0 1px rgba(0,0,0,0.1)",
        }}
      />

      {[1, 2].map((i) => (
        <MotionBox
          key={i}
          sx={{
            minHeight: 200,
            backgroundImage: `url(${images[i]})`,
            backgroundSize: "cover",
            borderRadius: 3,
            boxShadow: "0 0 0 1px rgba(0,0,0,0.1)",
          }}
        />
      ))}

      <MotionBox
        sx={{
          gridColumn: { md: "1" },
          height: 200,
          borderRadius: 3,
          backgroundImage: `url(${images[3]})`,
          backgroundSize: "cover",
        }}
      />
      <MotionBox
        sx={{
          gridColumn: { md: "2" },
          height: 200,
          borderRadius: 3,
          backgroundImage: `url(${images[4]})`,
          backgroundSize: "cover",
        }}
      />
    </MotionBox>
  );
};

export default BentoGrid;

Glassmorphism

A grid with frosted glass cards and inner content containers.
import React from "react";
import { Box } from "@mui/material";
import { motion } from "motion/react";

const MotionBox = motion.create(Box);

const GlassmorphismGrid = () => {
  const images = [
    "https://images.unsplash.com/photo-1506905925346-21bda4d32df4",
    "https://images.unsplash.com/photo-1507525428034-b723cf961d3e",
    "https://images.unsplash.com/photo-1441974231531-c6227db76b6e",
    "https://images.unsplash.com/photo-1469474968028-56623f02e42e",
  ];

  return (
    <MotionBox
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      sx={{
        display: "grid",
        gap: 2,
        padding: 2,
        gridTemplateColumns: {
          xs: "1fr",
          sm: "repeat(2,1fr)",
          md: "repeat(3,1fr)",
        },
      }}
    >
      {Array.from({ length: 6 }).map((_, index) => (
        <MotionBox
          key={index}
          sx={{
            height: 260,
            borderRadius: 4,
            backdropFilter: "blur(10px)",
            border: "1px solid rgba(255,255,255,0.2)",
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
            padding: 2,
          }}
        >
          <Box
            sx={{
              height: "90%",
              width: "90%",
              borderRadius: 3,
              backgroundImage: `url(${images[index % images.length]})`,
              backgroundSize: "cover",
              boxShadow: "0 4px 20px rgba(0,0,0,0.12)",
            }}
          />
        </MotionBox>
      ))}
    </MotionBox>
  );
};

export default GlassmorphismGrid;

Organic Shapes

A playful grid with smooth, irregular shapes using stable memoized radii.
import React from "react";
import { Box } from "@mui/material";
import { motion } from "motion/react";

const MotionBox = motion.create(Box);

const OrganicShapesGrid = () => {
  const images = [
    "https://images.unsplash.com/photo-1506905925346-21bda4d32df4",
    "https://images.unsplash.com/photo-1507525428034-b723cf961d3e",
    "https://images.unsplash.com/photo-1441974231531-c6227db76b6e",
  ];

  const shapes = React.useMemo(() => {
    return Array.from({ length: 6 }).map(() => {
      const rand = () => Math.floor(Math.random() * 20) + 25;
      return `${rand()}px ${rand()}px ${rand()}px ${rand()}px`;
    });
  }, []);

  return (
    <MotionBox
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      sx={{
        display: "grid",
        gap: 2,
        padding: 2,
        gridTemplateColumns: {
          xs: "1fr",
          sm: "repeat(2,1fr)",
          md: "repeat(3,1fr)",
        },
      }}
    >
      {Array.from({ length: 6 }).map((_, index) => (
        <MotionBox
          key={index}
          sx={{
            height: 260,
            borderRadius: shapes[index],
            backgroundImage: `url(${images[index % images.length]})`,
            backgroundSize: "cover",
            backgroundPosition: "center",
            boxShadow: "0 0 0 1px rgba(0,0,0,0.1)",
          }}
        />
      ))}
    </MotionBox>
  );
};

export default OrganicShapesGrid;

Minimal Cards

A clean card layout with soft shadows and rounded corners.
import React from "react";
import { Box } from "@mui/material";
import { motion } from "motion/react";

const MotionBox = motion.create(Box);

const MinimalCardsGrid = () => {
  const images = [
    "https://images.unsplash.com/photo-1506905925346-21bda4d32df4",
    "https://images.unsplash.com/photo-1507525428034-b723cf961d3e",
    "https://images.unsplash.com/photo-1441974231531-c6227db76b6e",
  ];

  return (
    <MotionBox
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      sx={{
        display: "grid",
        gap: 2,
        padding: 2,
        gridTemplateColumns: {
          xs: "1fr",
          sm: "repeat(2,1fr)",
          md: "repeat(3,1fr)",
        },
      }}
    >
      {Array.from({ length: 6 }).map((_, index) => (
        <MotionBox
          key={index}
          whileHover={{ scale: 1.02 }}
          sx={{
            height: 260,
            borderRadius: 2,
            backgroundColor: "background.paper",
            boxShadow: "0 0 0 1px rgba(0,0,0,0.1)",
            backgroundImage: `url(${images[index % images.length]})`,
            backgroundSize: "cover",
            backgroundPosition: "center",
          }}
        />
      ))}
    </MotionBox>
  );
};

export default MinimalCardsGrid;

Customization

All grid variants can be customized using Material-UI’s sx prop. Common customizations include:
  • Responsive breakpoints: Adjust gridTemplateColumns for different screen sizes
  • Spacing: Modify gap and padding values
  • Colors: Use theme palette values for backgrounds and borders
  • Heights: Customize minHeight and height properties
  • Animations: Adjust Framer Motion animation properties
  • Border radius: Change the roundness of corners

Dependencies

  • @mui/material - Material-UI components
  • framer-motion or motion/react - Animation library

Build docs developers (and LLMs) love