Copy for LLM
Grid
An aligned, vertically-scrolling multi-column layout: every cell shares the same track, so rows and columns line up. Drop any children in; it scrolls vertically and keeps a D-pad-focused child in view.
Installation
npx @glasskit-ui/cli add gridInstall the SDK (it provides GlassViewport, useDpad and the stylesheet), then copy these files into your project:
npm install @glasskit-ui/react// components/lib/utils.tsimport { clsx, type ClassValue } from "clsx";import { twMerge } from "tailwind-merge";export type { ClassValue };/** * Merge class names the shadcn way: clsx joins conditionals, tailwind-merge * de-dupes conflicting Tailwind utilities so a consumer's `className` override * wins (e.g. passing `px-2` beats the component's `px-6`). Lens components are * Tailwind utilities + `--gk-*` tokens, so this de-dupe matters. */export function cn(...inputs: ClassValue[]): string { return twMerge(clsx(inputs));}/** * Accessible name from a free-form `label` prop: the label itself when it's a * plain string, otherwise undefined (a ReactNode can't become an aria-label). */export function stringLabel(label: unknown): string | undefined { return typeof label === "string" ? label : undefined;}// components/glasskit/grid.tsx"use client";import { useLayoutEffect, useRef, type ReactNode } from "react";import { cn } from "../lib/utils";/** * <Grid> — an aligned, vertically-scrolling multi-column layout: every cell * shares the same track, so rows and columns line up. Drop any children in * (MediaThumb tiles, Pressable cards); the Grid scrolls vertically and keeps a * D-pad-focused child in view. Layout only: the children own their own * interactivity. */export function Grid({ columns = 2, children, className,}: { /** Number of columns (2, 3, or 4). */ columns?: 2 | 3 | 4; children: ReactNode; className?: string;}) { const scrollRef = useRef<HTMLDivElement>(null); // Keep a D-pad-focused child scrolled into view (focusin bubbles up). useLayoutEffect(() => { const el = scrollRef.current; if (!el) return; const onFocusIn = (e: FocusEvent) => { const t = e.target as HTMLElement | null; if (t && el.contains(t) && typeof t.scrollIntoView === "function") { t.scrollIntoView({ block: "nearest", behavior: "smooth" }); } }; el.addEventListener("focusin", onFocusIn); return () => el.removeEventListener("focusin", onFocusIn); }, []); return ( <div ref={scrollRef} data-cols={columns} className={cn("gk-grid", className)}> {children} </div> );}Usage
<Grid columns={2}> {photos.map((p) => ( <MediaThumb key={p.id} src={p.src} onSelect={() => open(p)} /> ))}</Grid>Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | 2 | 3 | 4 | 2 | Number of equal columns. |
children | ReactNode | — | The cells (e.g. MediaThumb tiles or Pressable cards). |
When to use
Reach for Grid when every cell is the same shape and you want them aligned in
neat rows: a grid of square thumbnails, a launcher-like set of equal cards. Pass
columns (2, 3, or 4) and it lays them out on equal tracks, scrolling
vertically.
Grid is layout only: the children own their interactivity (a
MediaThumb with onSelect, or a
Pressable).
Screen
The on-lens layout shell: a status region, a centered stage for the one task, and a cue region, with safe margins that keep the surface mostly black.
Masonry
A staggered, vertically-scrolling multi-column layout (the Pinterest / Photos look, where columns do not line up). Drop any children in; Masonry measures each and fills the shortest column, then keeps a D-pad-focused child in view.