React Grid System ⚛️

Published by Alicia's Notes 🚀, View original

A simple React component for implementing responsive grid-based layouts, without any dependencies. It uses the native CSS Grid Layout properties to align elements into columns and rows. It is written in TypeScript as a Styled-Component for React or React Native projects.

/*
 * Entry point for React grid system
 * React implementation of CSS grid layout written in TypeScript as a styled-component
 * Licensed under MIT - (C) Alicia Sykes 2020 <https://aliciasykes.com>
 */

// FILE 1 - layout/index.ts

import Grid from './Grid';
import Cell from './Cell';

export { Grid, Cell };
// FILE 2 - layout/cell.ts

import styled from 'styled-components';
import { maxWidth } from '@styles/media-queries';

interface CellProps {
  left?: number; // The horizontal starting position
  width?: number; // How many cells to span, horizontally
  top?: number; // The vertical starting position
  height?: number; // How many cells to span, vertically
  className?: string; // So Cell can optionally be used as a styled container
}

const Cell = styled.div<CellProps>`
  ${props => {
    const { left, width, top, height } = props;
    return `
    grid-column-start: ${left || 'unset'};
    grid-column-end: ${width ? `span ${width}` : 'unset'};
    grid-row-start: ${top || 'unset'};
    grid-row-end: ${height ? `span ${height}` : 'unset'};
    overflow-x: hidden;
    overflow-wrap: break-word;
    word-wrap: break-word;
    ${maxWidth.tablet(`
      // For tablet and above
      grid-column-start: unset;
      grid-row-start: unset; 
    `)};
  `;
  }}
`;

export default Cell;
// FILE 3 - layout/grid.ts

import React from 'react';
import styled from 'styled-components';
import { gridValues } from '@styles/sizes';
import { minWidth } from '@styles/media-queries';

const GridWrapper = styled.div<{ columns?: number; gutterOutside?: boolean }>`
  ${({ columns, gutterOutside }) => {
    const { maxGridWidth, gutter, minRowHeight, minColWidth, numCols } = gridValues(columns);

    const desktop = gridValues(columns, 8, 4);

    return `
      max-width: ${maxGridWidth};
      margin: 0 auto;
      display: grid;
      grid-gap: ${gutter};
      padding: 0 ${gutterOutside ? gutter : 0}
      grid-auto-rows: minmax(${minRowHeight}, auto);
      grid-template-columns: repeat(auto-fit, minmax(${minColWidth}, 1fr));

      // For tablet and above
      ${minWidth.tablet(`
        grid-template-columns: repeat(${numCols}, 1fr);
      `)};

      // For desktop and above
      ${minWidth.desktop(`
        max-width: ${desktop.maxGridWidth};
        grid-gap: ${desktop.gutter};
      `)}
    `;
  }}
`;

const Grid: React.FC<{ className?: string; columns?: number; gutterOutside?: boolean }> = ({
  className,
  columns,
  children,
  gutterOutside,
}) => (
  <GridWrapper className={className} columns={columns} gutterOutside={gutterOutside}>
    {children}
  </GridWrapper>
);

export default Grid;
// FILE 4 - layout/grid-dimensions.ts

expoert const gridValues = (columns = 12, colWidth = 8, gutterWidth = 2) => ({
  maxGridWidth: sizeUnit(columns * colWidth + (columns - 1) * gutterWidth),
  gutter: sizeUnit(gutterWidth),
  minRowHeight: sizeUnit(5),
  minColWidth: sizeUnit(colWidth),
  numCols: columns,
});