Created
December 30, 2025 18:02
-
-
Save z4nr34l/c7f493c9316d93d0bc0ad3dbefc85e08 to your computer and use it in GitHub Desktop.
React + tailwind responsive grid layout
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { cn } from "@workspace/ui/lib/utils"; | |
| import type { ReactNode } from "react"; | |
| type GridConfig = { | |
| cols: number; | |
| rows: number; | |
| }; | |
| type GridLayoutProps = { | |
| mobile: GridConfig; | |
| desktop: GridConfig; | |
| children: ReactNode; | |
| className?: string; | |
| }; | |
| type GridItemProps = { | |
| mobile: { | |
| colStart: number; | |
| colSpan: number; | |
| rowStart: number; | |
| rowSpan: number; | |
| }; | |
| desktop: { | |
| colStart: number; | |
| colSpan: number; | |
| rowStart: number; | |
| rowSpan: number; | |
| }; | |
| children: ReactNode; | |
| className?: string; | |
| }; | |
| export const GridItem = ({ | |
| mobile, | |
| desktop, | |
| children, | |
| className = "", | |
| }: GridItemProps) => ( | |
| <div | |
| className={cn("z-10 m-px h-[calc(100%-2px)] w-[calc(100%-2px)]", className)} | |
| data-grid-item="responsive" | |
| style={ | |
| { | |
| gridColumn: `${mobile.colStart} / span ${mobile.colSpan}`, | |
| gridRow: `${mobile.rowStart} / span ${mobile.rowSpan}`, | |
| ["--desktop-grid-column" as string]: `${desktop.colStart} / span ${desktop.colSpan}`, | |
| ["--desktop-grid-row" as string]: `${desktop.rowStart} / span ${desktop.rowSpan}`, | |
| } as React.CSSProperties | |
| } | |
| > | |
| {children} | |
| </div> | |
| ); | |
| export const GridLayout = ({ | |
| mobile, | |
| desktop, | |
| children, | |
| className = "", | |
| }: GridLayoutProps) => { | |
| const desktopCellWidth = 100 / desktop.cols; | |
| const desktopCellHeight = 100 / desktop.rows; | |
| // Generate horizontal lines for mobile (only rows - 1 divs) | |
| const mobileHorizontalLines = Array.from( | |
| { length: mobile.rows - 1 }, | |
| (_, i) => ( | |
| <div | |
| aria-hidden="true" | |
| className="pointer-events-none z-0 h-px bg-border md:hidden" | |
| key={`h-line-${i}`} | |
| style={{ | |
| gridColumn: "1 / -1", | |
| gridRow: i + 2, | |
| alignSelf: "start", | |
| marginTop: "-1px", | |
| }} | |
| /> | |
| ) | |
| ); | |
| return ( | |
| <div className={cn("-mt-px -ml-px relative w-[calc(100%+1px)]", className)}> | |
| <div | |
| className="grid-with-lines relative grid w-full" | |
| style={ | |
| { | |
| gridTemplateColumns: `repeat(${mobile.cols}, 1fr)`, | |
| gridTemplateRows: `repeat(${mobile.rows}, minmax(12.5vw, auto))`, | |
| ["--desktop-cols" as string]: desktop.cols, | |
| ["--desktop-rows" as string]: desktop.rows, | |
| ["--desktop-cell-width" as string]: `${desktopCellWidth}%`, | |
| ["--desktop-cell-height" as string]: `${desktopCellHeight}%`, | |
| } as React.CSSProperties | |
| } | |
| > | |
| {mobileHorizontalLines} | |
| {children} | |
| </div> | |
| </div> | |
| ); | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export function Example() { | |
| return ( | |
| <GridLayout desktop={{ cols: 12, rows: 8 }} mobile={{ cols: 8, rows: 8 }}> | |
| <GridItem | |
| className="flex flex-col justify-center space-y-8 bg-background p-6 md:items-center md:p-8 md:text-center" | |
| desktop={{ colStart: 2, colSpan: 10, rowStart: 2, rowSpan: 4 }} | |
| mobile={{ colStart: 1, colSpan: 8, rowStart: 1, rowSpan: 4 }} | |
| > | |
| <h1 className="text-balance font-bold text-3xl md:text-5xl"> | |
| {t("title")} | |
| </h1> | |
| <p className="text-balance text-muted-foreground">{t("description")}</p> | |
| </GridItem> | |
| </GridLayout> | |
| ) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment