Patterns
Gallery
One viewer for a set of items, and a trigger for each. A trigger can be any element, usually a button holding the thumbnail. When the viewer closes, it flies back to the trigger of the item it shows and focus returns there.
Loading the live example…
basic.tsx
import { itemLabel } from "@ogdakke/fluidbox";
import { Fluidbox } from "@ogdakke/fluidbox/react";
import { photos } from "./data";
export function Basic() {
return (
<Fluidbox.Root items={photos}>
<div className="pattern-grid">
{photos.map((photo) => (
<Fluidbox.Trigger
key={photo.src}
item={photo}
className="pattern-thumb"
>
<img src={photo.src} alt={itemLabel(photo)} />
</Fluidbox.Trigger>
))}
</div>
{/* Without a Viewer, the viewer has these same three buttons. */}
<Fluidbox.Viewer>
<Fluidbox.Previous />
<Fluidbox.Next />
<Fluidbox.Close />
</Fluidbox.Viewer>
</Fluidbox.Root>
);
}Basic.vue
<script setup lang="ts">
import { itemLabel } from "@ogdakke/fluidbox";
import { Fluidbox } from "@ogdakke/fluidbox/vue";
import { photos } from "./data";
</script>
<template>
<!-- Without a Viewer, the viewer has the default Previous, Next and Close. -->
<Fluidbox.Root :items="photos">
<div class="pattern-grid">
<Fluidbox.Trigger
v-for="photo in photos"
:key="photo.id"
:item="photo"
class="pattern-thumb"
>
<img :src="photo.src" :alt="itemLabel(photo)" />
</Fluidbox.Trigger>
</div>
</Fluidbox.Root>
</template>basic.tsx
import { For } from "solid-js";
import { itemLabel } from "@ogdakke/fluidbox";
import { Fluidbox } from "@ogdakke/fluidbox/solid";
import { photos } from "./data";
export function Basic() {
return (
<Fluidbox.Root items={photos}>
<div class="pattern-grid">
<For each={photos}>
{(photo) => (
<Fluidbox.Trigger item={photo} class="pattern-thumb">
<img src={photo.src} alt={itemLabel(photo)} />
</Fluidbox.Trigger>
)}
</For>
</div>
{/* Without a Viewer, the viewer has these three by default. */}
<Fluidbox.Viewer>
<Fluidbox.Previous />
<Fluidbox.Next />
<Fluidbox.Close />
</Fluidbox.Viewer>
</Fluidbox.Root>
);
}basic.ts
import { Component } from "@angular/core";
import { itemLabel } from "@ogdakke/fluidbox";
import { FluidboxModule } from "@ogdakke/fluidbox/angular";
import { photos } from "./data";
@Component({
selector: "pattern-basic",
standalone: true,
imports: [FluidboxModule],
template: `
<div fluidboxRoot [items]="photos" class="pattern-grid">
@for (photo of photos; track photo.id) {
<button [fluidboxTrigger]="photo" class="pattern-thumb">
<img [src]="photo.src" [alt]="label(photo)" />
</button>
}
<!-- Without a viewer template these three are the default; with one, you place them. -->
<ng-template fluidboxViewer>
<button fluidboxPrevious></button>
<button fluidboxNext></button>
<button fluidboxClose></button>
</ng-template>
</div>
`,
})
export class Basic {
readonly photos = photos;
readonly label = itemLabel;
}basic.html
<fluidbox-gallery class="pattern-grid">
<fluidbox-item item-id="photo-aurora">
<button slot="trigger" type="button" class="pattern-thumb">
<img src="/art/aurora.svg" alt="Aurora over the tundra" />
</button>
<template slot="content">
<img src="/art/aurora.svg" alt="Aurora over the tundra" width="1100" height="1650" />
</template>
</fluidbox-item>
<fluidbox-item item-id="photo-ridge">
<button slot="trigger" type="button" class="pattern-thumb">
<img src="/art/ridge.svg" alt="Night ridge" />
</button>
<template slot="content">
<img src="/art/ridge.svg" alt="Night ridge" width="1200" height="1500" />
</template>
</fluidbox-item>
<fluidbox-item item-id="photo-fjord">
<button slot="trigger" type="button" class="pattern-thumb">
<img src="/art/fjord.svg" alt="Fjord in the blue hour" />
</button>
<template slot="content">
<img src="/art/fjord.svg" alt="Fjord in the blue hour" width="1200" height="1600" />
</template>
</fluidbox-item>
<fluidbox-item item-id="photo-lagoon">
<button slot="trigger" type="button" class="pattern-thumb">
<img src="/art/lagoon.svg" alt="Lagoon after sunset" />
</button>
<template slot="content">
<img src="/art/lagoon.svg" alt="Lagoon after sunset" width="1800" height="1200" />
</template>
</fluidbox-item>
</fluidbox-gallery>basic.ts
import { createFluidbox, itemLabel } from "@ogdakke/fluidbox";
import { photos } from "./data";
export function mountBasic(root: HTMLElement) {
// The viewer has Previous, Next and Close buttons unless you draw your own.
const fluidbox = createFluidbox({ items: photos });
const grid = document.createElement("div");
grid.className = "pattern-grid";
photos.forEach((photo, index) => {
const button = document.createElement("button");
button.type = "button";
button.className = "pattern-thumb";
button.append(Object.assign(new Image(), { src: photo.src, alt: itemLabel(photo) }));
grid.append(button);
fluidbox.bind(button, index);
});
root.append(grid);
return () => {
// Also unbinds the buttons.
fluidbox.destroy();
grid.remove();
};
}- The viewer has Previous, Next and Close buttons until you give it content of your own. Then the framework
Controlspart,<fluidbox-controls>or thecontrolsoption keeps them. - In plain JavaScript,
fluidbox.bind(button, index)makes each button a trigger, andfluidbox.destroy()unbinds them all. - The trigger's image is where the flight starts and ends. Mark another element with
data-fluidbox-originto fly from it instead (see Rich origins).