# TallStackUI: Gallery > TallStackUI is a TALL Stack (Tailwind CSS, Alpine.js, Laravel, Livewire) > component library providing 80+ Blade components for building modern web interfaces. An image gallery component with three layouts — a uniform responsive grid, a masonry column flow, and a feature layout with one large cover above a thumbnail row. Every layout supports an opt-in lightbox that expands an image fullscreen with prev/next navigation, keyboard control, and optional captions. ## Basic Usage ```blade ``` ```blade ``` ## Layouts The layout is chosen by a boolean flag. They are mutually exclusive, and `grid` applies when none is given. ```blade ``` ### Grid Uniform tiles in a responsive grid. Tile shape comes from `ratio`, and the image is cropped with `object-cover`. ```blade ``` ### Masonry Equal-width columns where each image keeps its natural height, built on CSS multi-column. Reading order runs down each column before moving to the next: images 1, 2, 3 fill the first column, 4, 5, 6 the second. The `ratio` attribute does not apply. ```blade ``` Supply `width` and `height` on each image here. Without them the layout shifts as images load, because no aspect-ratio class reserves the space in advance. ### Feature One large cover image above a row of up to `limit - 1` thumbnails. ```blade ``` The cover is the image flagged `'cover' => true`, falling back to the first entry. When the array holds more images than `limit`, the last thumbnail gets a `+N` overlay where `N = count($images) - $limit`. Clicking it opens the lightbox at that image, and the arrows browse the whole array — nothing is dropped. When the array holds fewer images than `limit`, the row simply renders fewer tiles and no overlay appears. In this layout `ratio` controls the cover image and defaults to `video`; thumbnails are always square. #### Thumbnail position `thumbnails` moves the thumbnail row beside the cover, which is the usual product-page arrangement. Below the `sm` breakpoint they always wrap under the cover, so the layout stays usable on mobile. ```blade ``` The side column is absolutely positioned with `inset-y-0`, so it inherits the cover's height rather than growing past it, and scrolls inside with `custom-scrollbar`. The cover reserves the space with `ml-26`/`mr-26` — the column's `w-24` plus the `gap-2`. Raising `limit` therefore adds scrollable thumbnails instead of making the column taller than the image beside it. ## Sizing and scrolling Attributes from the consumer are merged onto the root element, so `class`, `id`, `style`, `data-*` and Livewire directives all reach it. Use a width utility to contain the component: ```blade ``` `height` caps the tile area and scrolls inside it, taking the same values as ``: `40`, `60`, `80` or `96`, mapping to `max-h-40` and friends. The scrolling wrapper is rendered by the component and carries `custom-scrollbar`, so it matches the rest of the library without any work from the consumer. The `header` and `footer` slots stay outside the scrolling region, and the lightbox is unaffected because it teleports to the ``. ```blade ``` An arbitrary height can still be had with utilities, since attributes reach the root — but then the scrollbar styling is on you: ```blade ``` ## Attributes | Attribute | Type | Default | Description | |--------------|---------------------|---------|-------------------------------------------------------------------------------| | images | Collection\|array | — | Required. The images to render | | grid | bool | false | Uniform responsive grid. Applied when no layout flag is given | | masonry | bool | false | Multi-column flow with natural image heights | | feature | bool | false | Large cover above a thumbnail row | | columns | int | 3 | Column count (2–6) for `grid` and `masonry` | | ratio | string | square | Tile shape: `square`, `video` or `portrait`. Defaults to `video` on `feature` | | limit | int | 7 | Total tiles rendered by `feature`, cover included | | thumbnails | string | bottom | Thumbnail position on `feature`: `bottom`, `left` or `right` | | height | string\|null | null | Caps the tile area and scrolls inside it: `40`, `60`, `80` or `96` | | clickable | bool | false | Enables the lightbox | | navigable | bool | false | Prev/next buttons and arrow keys inside the lightbox | | caption | string\|null | null | Lightbox caption layout: `overlay` or `footer` | | without-loop | bool | false | Stops the lightbox from wrapping around at the ends | | round | bool | false | Rounds the tile corners | | header | ComponentSlot\|null | null | Header slot content displayed above the gallery | | footer | ComponentSlot\|null | null | Footer slot content displayed below the gallery | ## Image Object Structure | Key | Type | Required | Description | |-------------|--------|----------|---------------------------------------------------------| | src | string | Yes | Image source URL | | alt | string | Yes | Alt text for accessibility | | title | string | No | Lightbox caption title | | description | string | No | Lightbox caption description below the title | | width | int | No | Intrinsic width, reserving space while the image loads | | height | int | No | Intrinsic height, reserving space while the image loads | | url | string | No | Makes the tile a link. Ignored when `clickable` is set | | target | string | No | Link target (e.g., `_blank`) | | cover | bool | No | Marks this image as the cover in the `feature` layout | ## Slots | Slot | Description | |--------|------------------------------------| | header | Content rendered above the gallery | | footer | Content rendered below the gallery | ## Validation Constraints - The `images` attribute is required and cannot be empty. - The `grid`, `masonry` and `feature` flags cannot be used together. - The `caption` must be either `overlay` or `footer`. - The `caption`, `navigable` and `without-loop` require `clickable` to be enabled. - The `columns` must be between 2 and 6. - The `ratio` must be `square`, `video` or `portrait`. - The `limit` must be at least 2. - The `columns` cannot be used with `feature`. - The `limit` can only be used with `feature`. - The `ratio` cannot be used with `masonry`. - The `thumbnails` must be `bottom`, `left` or `right`. - The `thumbnails` can only be used with `feature`. - The `height` must be `40`, `60`, `80` or `96`. Attributes passed to a layout that ignores them raise an exception rather than being silently dropped. ## Clickable (Lightbox) Add `clickable` to let users open any tile fullscreen. The lightbox renders an overlay teleported to the `` (so it never gets trapped inside ancestors that create a containing block) with a close button at the top-right, and also closes on `Esc` or by clicking the dark backdrop. ```blade ``` When `clickable` is set, each image's `url`/`target` is ignored — the click expands the image instead of navigating. Without `clickable` the component renders no JavaScript at all: tiles become plain links, or plain images when no `url` is given. ## Lightbox Caption ```blade ``` `overlay` keeps the caption visually attached to the image (good for short titles); `footer` separates the caption onto its own row beneath the image (good for long descriptions). ## Lightbox Navigation Add `navigable` together with `clickable` to browse the whole gallery from inside the lightbox, with prev/next buttons on the sides and the `←` / `→` keys. ```blade ``` By default navigation wraps around at both ends. Add `without-loop` to stop at the first and last image, disabling the button that would go past the edge. ```blade ``` ## Events When `clickable` is enabled, the root element dispatches: | Event | Detail | Fired when | |------------|----------------------|-----------------------------| | `expand` | `{ image }` | The lightbox opens | | `collapse` | `{ image: null }` | The lightbox closes | | `next` | `{ current, image }` | The lightbox steps forward | | `previous` | `{ current, image }` | The lightbox steps backward | ```blade ``` ## Performance Every tile renders with `loading="lazy"` and `decoding="async"`, so the browser skips downloading off-screen images, and with `content-visibility: auto` plus `contain-intrinsic-size`, so it also skips their layout and paint. Tiles render as real HTML through a server-side loop rather than a client-side template, keeping images indexable and browser find working. Supply `width` and `height` on each image to avoid layout shift, which matters most in the `masonry` layout. The `content-visibility` declaration lives in its own customization block and can be dropped: ```php TallStackUi::customize()->gallery()->block('tile.performance', ''); ``` ## Customization ```php TallStackUi::customize()->gallery()->block('tile.rounded', 'rounded-2xl'); TallStackUi::customize() ->gallery() ->block('grid.gap') ->replace('gap-2', 'gap-4'); // Redefine the breakpoints behind a column count TallStackUi::customize()->gallery()->block('grid.columns.4', 'grid-cols-1 md:grid-cols-4'); ``` Available blocks: `wrapper`, `scroll`, `height.*`, `grid.*`, `masonry.*`, `feature.*`, `tile.*` and `lightbox.*`. The feature wrappers are keyed by thumbnail position, so each arrangement can be restyled on its own: ```php TallStackUi::customize()->gallery()->block('feature.thumbnails.wrapper.left', 'grid grid-cols-1 gap-3 sm:w-32'); ```