UIPackage

Grid

React layout
Edit on GitHub

Responsive CSS grid container with `cols`, `gap`, and breakpoint props. A small but useful primitive for laying out card grids, KPI tiles, and form sections without writing repetitive Tailwind classes.

Also available for Vue ->

Installation

$ npx shadcn@latest add https://react.uipkge.dev/r/react/grid.json

Or with the named registry: npx shadcn@latest add @uipkge-react/grid

Examples

Props

Name Type / Values Default Required
cols Cols 1 optional
gap GapToken 4 optional

Files (2)

  • components/ui/grid/grid.tsx 3.5 kB
    import * as React from 'react'
    import { cn } from '@/lib/utils'
    
    // Responsive CSS-grid container. Pass an integer for fixed column count, or
    // a breakpoint map for responsive layouts: `{ base: 1, sm: 2, lg: 3 }`.
    //
    // Examples:
    //   <Grid cols={3} gap={4}>...</Grid>
    //   <Grid cols={{ base: 1, sm: 2, lg: 4 }} gap={6}>...</Grid>
    //
    // Tailwind v4's content scanner cannot see classnames built from
    // `grid-cols-${n}` template strings, so we map each supported value
    // to a complete class string. The scanner sees the literal classes
    // and emits them in the consumer's production CSS.
    type ColIndex = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
    type Cols = ColIndex | Partial<Record<'base' | 'sm' | 'md' | 'lg' | 'xl', ColIndex>>
    type GapToken = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | 16
    
    const COLS_BASE: Record<ColIndex, string> = {
      1: 'grid-cols-1',
      2: 'grid-cols-2',
      3: 'grid-cols-3',
      4: 'grid-cols-4',
      5: 'grid-cols-5',
      6: 'grid-cols-6',
      7: 'grid-cols-7',
      8: 'grid-cols-8',
      9: 'grid-cols-9',
      10: 'grid-cols-10',
      11: 'grid-cols-11',
      12: 'grid-cols-12',
    }
    const COLS_SM: Record<ColIndex, string> = {
      1: 'sm:grid-cols-1',
      2: 'sm:grid-cols-2',
      3: 'sm:grid-cols-3',
      4: 'sm:grid-cols-4',
      5: 'sm:grid-cols-5',
      6: 'sm:grid-cols-6',
      7: 'sm:grid-cols-7',
      8: 'sm:grid-cols-8',
      9: 'sm:grid-cols-9',
      10: 'sm:grid-cols-10',
      11: 'sm:grid-cols-11',
      12: 'sm:grid-cols-12',
    }
    const COLS_MD: Record<ColIndex, string> = {
      1: 'md:grid-cols-1',
      2: 'md:grid-cols-2',
      3: 'md:grid-cols-3',
      4: 'md:grid-cols-4',
      5: 'md:grid-cols-5',
      6: 'md:grid-cols-6',
      7: 'md:grid-cols-7',
      8: 'md:grid-cols-8',
      9: 'md:grid-cols-9',
      10: 'md:grid-cols-10',
      11: 'md:grid-cols-11',
      12: 'md:grid-cols-12',
    }
    const COLS_LG: Record<ColIndex, string> = {
      1: 'lg:grid-cols-1',
      2: 'lg:grid-cols-2',
      3: 'lg:grid-cols-3',
      4: 'lg:grid-cols-4',
      5: 'lg:grid-cols-5',
      6: 'lg:grid-cols-6',
      7: 'lg:grid-cols-7',
      8: 'lg:grid-cols-8',
      9: 'lg:grid-cols-9',
      10: 'lg:grid-cols-10',
      11: 'lg:grid-cols-11',
      12: 'lg:grid-cols-12',
    }
    const COLS_XL: Record<ColIndex, string> = {
      1: 'xl:grid-cols-1',
      2: 'xl:grid-cols-2',
      3: 'xl:grid-cols-3',
      4: 'xl:grid-cols-4',
      5: 'xl:grid-cols-5',
      6: 'xl:grid-cols-6',
      7: 'xl:grid-cols-7',
      8: 'xl:grid-cols-8',
      9: 'xl:grid-cols-9',
      10: 'xl:grid-cols-10',
      11: 'xl:grid-cols-11',
      12: 'xl:grid-cols-12',
    }
    const GAP: Record<GapToken, string> = {
      0: 'gap-0',
      1: 'gap-1',
      2: 'gap-2',
      3: 'gap-3',
      4: 'gap-4',
      5: 'gap-5',
      6: 'gap-6',
      8: 'gap-8',
      10: 'gap-10',
      12: 'gap-12',
      16: 'gap-16',
    }
    
    export interface GridProps extends React.HTMLAttributes<HTMLDivElement> {
      cols?: Cols
      gap?: GapToken
    }
    
    const Grid = React.forwardRef<HTMLDivElement, GridProps>(
      ({ cols = 1, gap = 4, className, children, ...props }, ref) => {
        const colsClass =
          typeof cols === 'number'
            ? COLS_BASE[cols]
            : [
                cols.base != null ? COLS_BASE[cols.base] : '',
                cols.sm != null ? COLS_SM[cols.sm] : '',
                cols.md != null ? COLS_MD[cols.md] : '',
                cols.lg != null ? COLS_LG[cols.lg] : '',
                cols.xl != null ? COLS_XL[cols.xl] : '',
              ]
                .filter(Boolean)
                .join(' ')
    
        const gapClass = GAP[gap]
    
        return (
          <div
            ref={ref}
            data-uipkge=""
            data-slot="grid"
            className={cn('grid', colsClass, gapClass, className)}
            {...props}
          >
            {children}
          </div>
        )
      },
    )
    Grid.displayName = 'Grid'
    
    export { Grid }
  • components/ui/grid/index.ts 0 kB
    export { Grid, type GridProps } from './grid'

Raw manifest: https://react.uipkge.dev/r/react/grid.json