Skip to content

Seungwoo321/tailwind-grid-layout

Repository files navigation

Tailwind Grid Layout

A modern, lightweight grid layout system for React built with Tailwind CSS. A powerful alternative to react-grid-layout with full feature parity and a smaller bundle size.

npm version license bundle size

Live Demo | Storybook

English | 한국어

Tailwind Grid Layout Screenshot

Features

  • Full Feature Parity with react-grid-layout
  • Lightweight - Smaller bundle size (~15KB gzip)
  • Tailwind Native - Built with Tailwind CSS v4
  • Responsive - Works on all screen sizes
  • Mobile Touch - Full touch device support
  • TypeScript - Full TypeScript support
  • Well Tested - 100% test coverage

Installation

npm install tailwind-grid-layout

Requirements

  • React 19+
  • Tailwind CSS 4.x

Quick Start

import { useState } from 'react'
import { GridContainer } from 'tailwind-grid-layout'
import type { GridItem } from 'tailwind-grid-layout'

const initialItems: GridItem[] = [
  { id: '1', x: 0, y: 0, w: 3, h: 2 },
  { id: '2', x: 3, y: 0, w: 5, h: 3 },
  { id: '3', x: 8, y: 0, w: 4, h: 2 },
]

function App() {
  const [items, setItems] = useState(initialItems)

  return (
    <GridContainer
      items={items}
      cols={12}
      rowHeight={80}
      gap={16}
      onLayoutChange={setItems}
    >
      {(item) => (
        <div className="bg-white rounded-xl p-4 shadow">
          Item {item.id}
        </div>
      )}
    </GridContainer>
  )
}

Components

GridContainer

Basic grid container with drag and resize support.

<GridContainer
  items={items}
  cols={12}
  rowHeight={80}
  gap={16}
  isDraggable={true}
  isResizable={true}
  resizeHandles={['se', 'sw', 'ne', 'nw', 'n', 's', 'e', 'w']}
  onLayoutChange={setItems}
>
  {(item) => <div>Item {item.id}</div>}
</GridContainer>

GridContainer Props

Prop Type Default Description
items GridItem[] required Array of grid items
children (item: GridItem) => ReactNode required Render function for each item
cols number 12 Number of columns
rowHeight number 60 Height of each row in pixels
gap number 16 Gap between items in pixels
margin [number, number] [gap, gap] Margin [horizontal, vertical]
containerPadding [number, number] [16, 16] Container padding [horizontal, vertical]
maxRows number undefined Maximum number of rows
isDraggable boolean true Enable/disable dragging
isResizable boolean true Enable/disable resizing
preventCollision boolean false Prevent items from colliding
allowOverlap boolean false Allow items to overlap
isBounded boolean true Keep items within container bounds
compactType 'vertical' | 'horizontal' | null 'vertical' Compaction direction
resizeHandles ResizeHandle[] ['se'] Resize handle positions
draggableCancel string undefined CSS selector for non-draggable elements
draggableHandle string undefined CSS selector for drag handle
autoSize boolean true Auto-adjust container height
preserveInitialHeight boolean false Preserve initial layout height
transformScale number 1 Transform scale for nested transforms
className string undefined Additional CSS classes
style CSSProperties undefined Additional inline styles

GridContainer Callbacks

Callback Type Description
onLayoutChange (layout: GridItem[]) => void Called when layout changes
onDragStart (layout, oldItem, newItem, placeholder, e, element) => void Called when drag starts
onDrag (layout, oldItem, newItem, placeholder, e, element) => void Called during drag
onDragStop (layout, oldItem, newItem, placeholder, e, element) => void Called when drag ends
onResizeStart (layout, oldItem, newItem, placeholder, e, element) => void Called when resize starts
onResize (layout, oldItem, newItem, placeholder, e, element) => void Called during resize
onResizeStop (layout, oldItem, newItem, placeholder, e, element) => void Called when resize ends

ResponsiveGridContainer

Responsive grid with breakpoint-based layouts.

import { ResponsiveGridContainer, WidthProvider } from 'tailwind-grid-layout'

const ResponsiveGrid = WidthProvider(ResponsiveGridContainer)

const layouts = {
  lg: [{ id: '1', x: 0, y: 0, w: 6, h: 2 }],
  md: [{ id: '1', x: 0, y: 0, w: 10, h: 2 }],
  sm: [{ id: '1', x: 0, y: 0, w: 6, h: 2 }],
}

<ResponsiveGrid
  layouts={layouts}
  breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
  cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
  onLayoutChange={(layout, layouts) => console.log(layouts)}
  onBreakpointChange={(breakpoint, cols) => console.log(breakpoint)}
>
  {(item) => <div>Item {item.id}</div>}
</ResponsiveGrid>

ResponsiveGridContainer Props

Inherits all GridContainer props except items, cols, and onLayoutChange.

Prop Type Default Description
layouts { [breakpoint: string]: GridItem[] } required Layout for each breakpoint
breakpoints { [breakpoint: string]: number } { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 } Breakpoint widths
cols { [breakpoint: string]: number } { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 } Columns per breakpoint
onLayoutChange (layout: GridItem[], layouts: BreakpointLayouts) => void undefined Called when layout changes
onBreakpointChange (breakpoint: string, cols: number) => void undefined Called when breakpoint changes
width number undefined Container width (for WidthProvider)

DroppableGridContainer

Grid with external drag-and-drop support.

import { DroppableGridContainer } from 'tailwind-grid-layout'

<DroppableGridContainer
  items={items}
  droppingItem={{ w: 2, h: 2 }}
  onDrop={(newItem) => setItems([...items, newItem])}
>
  {(item) => <div>Item {item.id}</div>}
</DroppableGridContainer>

DroppableGridContainer Props

Inherits all GridContainer props except onDrop.

Prop Type Default Description
droppingItem Partial<GridItem> { w: 2, h: 2 } Size of dropping item
onDrop (item: GridItem) => void undefined Called when item is dropped

WidthProvider

HOC that provides width to ResponsiveGridContainer.

import { ResponsiveGridContainer, WidthProvider } from 'tailwind-grid-layout'

const ResponsiveGrid = WidthProvider(ResponsiveGridContainer)

// Or with options
const ResponsiveGrid = WidthProvider(ResponsiveGridContainer)

<ResponsiveGrid measureBeforeMount={true}>
  {/* ... */}
</ResponsiveGrid>

WidthProvider Props

Prop Type Default Description
measureBeforeMount boolean false Measure width before mounting

GridItem Properties

Property Type Required Description
id string Yes Unique identifier
x number Yes X position in grid units
y number Yes Y position in grid units
w number Yes Width in grid units
h number Yes Height in grid units
minW number No Minimum width
maxW number No Maximum width
minH number No Minimum height
maxH number No Maximum height
static boolean No Make item unmovable and unresizable
isDraggable boolean No Override container's isDraggable
isResizable boolean No Override container's isResizable
className string No Additional CSS class for item

Resize Handles

Available resize handle positions:

Handle Position
n North (top center)
s South (bottom center)
e East (right center)
w West (left center)
ne North-East (top right corner)
nw North-West (top left corner)
se South-East (bottom right corner)
sw South-West (bottom left corner)

Utility Functions

import { generateLayouts, generateResponsiveLayouts } from 'tailwind-grid-layout'

// Generate layout from items
const layout = generateLayouts(items)

// Generate responsive layouts
const responsiveLayouts = generateResponsiveLayouts(items, breakpoints, cols)

Comparison with react-grid-layout

Feature react-grid-layout tailwind-grid-layout
Bundle Size ~30KB ~15KB
Tailwind Native No Yes
TypeScript Yes Yes
Touch Support Yes Yes
Responsive Yes Yes
External CSS Required Not needed

License

MIT © Seungwoo, Lee

About

A Tailwind CSS compatible grid layout system - Alternative to react-grid-layout

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages