Auto Grid
A self-adjusting grid that fits as many tracks as the container allows
Card 1
Card 2
Card 3
Card 4
Card 5
Card 6
import { AutoGrid } from '@/components/auto-grid';
const Card = ({ children }: { children: React.ReactNode }) => (
<div className="rounded-lg border border-border bg-background-secondary p-4 text-center text-foreground-secondary text-sm aspect-square">
{children}
</div>
);
export const meta = { layout: 'padded' };
export default function AutoGridPreview() {
return (
<AutoGrid minItemWidth="12rem">
<Card>Card 1</Card>
<Card>Card 2</Card>
<Card>Card 3</Card>
<Card>Card 4</Card>
<Card>Card 5</Card>
<Card>Card 6</Card>
</AutoGrid>
);
} Dependencies
Source Code
import type { VariantProps } from 'cva';
import { Slot } from '@/components/slot';
import { cn, cva } from '@/lib/utils/classnames';
const autoGridStyle = cva({
base: 'grid grid-cols-[repeat(auto-fit,minmax(min(100%,var(--auto-grid-min)),1fr))]',
variants: {
gap: {
none: 'gap-0',
xs: 'gap-2',
sm: 'gap-3',
md: 'gap-4 md:gap-6',
lg: 'gap-6 md:gap-8',
xl: 'gap-8 md:gap-12',
},
},
defaultVariants: {
gap: 'md',
},
});
interface AutoGridProps
extends React.ComponentPropsWithRef<'div'>,
VariantProps<typeof autoGridStyle> {
/**
* Minimum width of each track. Tracks below this width wrap to the next row.
* The `min(100%, …)` guard prevents overflow when the container is narrower
* than this value. Accepts any CSS length. Defaults to `16rem`.
*/
minItemWidth?: string;
asChild?: boolean;
}
const AutoGrid = ({
ref,
className,
gap,
minItemWidth = '16rem',
style,
asChild,
...rest
}: AutoGridProps) => {
const Comp = asChild ? Slot : 'div';
return (
<Comp
ref={ref}
className={cn(autoGridStyle({ gap }), className)}
style={{ '--auto-grid-min': minItemWidth, ...style }}
{...rest}
/>
);
};
export type { AutoGridProps };
export { AutoGrid, autoGridStyle }; Server component. No
'use client'— layout primitive; no hooks or own handlers.
AutoGrid creates as many equal-width columns as fit the container, wrapping
the rest to new rows — no breakpoints required. Each track is at least
minItemWidth wide. Use it for card galleries, stat grids, and template
pickers where the column count should follow available width.
The min(100%, …) guard in the track definition prevents horizontal overflow
when the container is narrower than minItemWidth.
Anatomy
<AutoGrid minItemWidth="18rem">
<Card />
<Card />
<Card />
</AutoGrid>
API Reference
AutoGrid
Extends the div element.
| Prop | Default | Type |
|---|---|---|
minItemWidth | "16rem" | string |
gap | "md" | "none""xs""sm""md""lg""xl" |
asChild | - | boolean |
Examples
Default
Card 1
Card 2
Card 3
Card 4
Card 5
Card 6
import { AutoGrid } from '@/components/auto-grid';
const Card = ({ children }: { children: React.ReactNode }) => (
<div className="rounded-lg border border-border bg-background-secondary p-4 text-center text-foreground-secondary text-sm aspect-square">
{children}
</div>
);
export const meta = { layout: 'padded' };
export default function AutoGridPreview() {
return (
<AutoGrid minItemWidth="12rem">
<Card>Card 1</Card>
<Card>Card 2</Card>
<Card>Card 3</Card>
<Card>Card 4</Card>
<Card>Card 5</Card>
<Card>Card 6</Card>
</AutoGrid>
);
} Previous
App Shell
Next
Avatar