Maze Pattern

A maze-themed background with customizable colors and size.

Find Your Way

1. Copy the component file

Create a new file called maze-pattern-background.jsx in your reusable components folder (for example /src/components/) and paste the following code into it.

maze-pattern-background.jsx

import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import styles from "./maze-pattern-background.module.css";

const MazePatternBackground = (props) => {
  const {
    backgroundColor = "#000000",
    mazeColor = "#6572e6",
    mazeSize = 20,
    children,
    className,
    wrapperProps = {},
    wrapperTagName = "div",
    ...rest
  } = props;

  const {
    className: wrapperClassName = "",
    ...restWrapperProps
  } = wrapperProps;

  const Wrapper = wrapperTagName || "div";

  const containerRef = useRef(null);
  const canvasRef = useRef(null);

  const [mounted, setMounted] = useState(false);
  const [width, setWidth] = useState(0);
  const [height, setHeight] = useState(0);

  const ctx = useMemo(() => {
    return canvasRef.current?.getContext("2d");
  }, [canvasRef.current]);

  const render = useCallback(() => {
    ctx.fillStyle = backgroundColor;
    ctx.fillRect(0, 0, width, height);
    ctx.save();
    for (let y = 0; y < height; y += mazeSize) {
      for (let x = 0; x < width; x += mazeSize) {
        ctx.beginPath();
        if (Math.random() < 0.5) {
          ctx.moveTo(x, y);
          ctx.lineTo(x + mazeSize, y + mazeSize);
        } else {
          ctx.moveTo(x + mazeSize, y);
          ctx.lineTo(x, y + mazeSize);
        }
        ctx.strokeStyle = mazeColor;
        ctx.lineWidth = 1;
        ctx.stroke();
        ctx.closePath();
      }
    }
    ctx.restore();
  }, [ctx, backgroundColor, mazeColor, width, height, mazeSize]);

  useEffect(() => {
    const updateContainerDimensions = () => {
      const {
        width,
        height,
      } = containerRef.current.getBoundingClientRect();
      setWidth(width);
      setHeight(height);
    };
    const resizeObserver = new ResizeObserver(updateContainerDimensions);
    resizeObserver.observe(containerRef.current);
    updateContainerDimensions();
    setMounted(true);
    return () => {
      resizeObserver.disconnect();
    };
  }, []);

  useLayoutEffect(() => {
    if (!mounted) return;
    render();
  }, [render]);

  return (
    <div
      {...rest}
      ref={containerRef}
      className={[
        className,
        styles["maze-pattern-background"]
      ].join(" ")}
    >
      <canvas
        aria-hidden={true}
        width={width}
        height={height}
        ref={canvasRef}
      />
      <Wrapper
        {...restWrapperProps}
        className={[
          wrapperClassName,
          styles["wrapper"]
        ].join(" ")}
      >
        {children}
      </Wrapper>
    </div>
  )
};

export default memo(MazePatternBackground);

2. Copy the CSS module file

In the same folder, create a file called maze-pattern-background.module.css and paste the following CSS.

maze-pattern-background.module.css

.maze-pattern-background {
  position: relative;

  > canvas {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
  }

  > .wrapper {
    position: relative;
    z-index: 2;
  }
}

3. Use the component

Now you can import and use the component anywhere in your project.

maze-pattern-background-preview.jsx

import MazePatternBackground from "@/components/backgrounds/maze-pattern-background/maze-pattern-background";

const MazePatternBackgroundPreview = () => {
  return (
    <MazePatternBackground
      style={{
        width: "100%",
        height: "100%"
      }}
      wrapperProps={{
        style: {
          height: "100%",
          background: "rgba(0,0,0,0.25)",
          display: "grid",
          placeItems: "center",
          color: "#fff",
        }
      }}
      mazeSize={10}
    >
      <h1>Find Your Way</h1>
    </MazePatternBackground>
  );
};

export default MazePatternBackgroundPreview;

Props

Configure the component with the following props:

PropTypeRequiredDefaultDescription
backgroundColorstringNo"#000000"Background color behind the maze.
mazeColorstringNo"#6572e6"Color of the maze lines.
mazeSizenumberNo20Size of each maze cell in pixels.
childrenReactNodeYesContent rendered on top of the maze background.
classNamestringNoAdditional CSS classes applied to the main container.
wrapperPropsReact.HTMLAttributes<any>NoExtra props passed to the wrapper element containing the children.
wrapperTagNamestringNo"div"HTML tag used as the wrapper element around the children.