Skip to content
Components

Mosaic

Arrange related content into a responsive grid.

TS
import { … } from "@fungi.computer/caps/blocks/mosaic";

Photos

TSX
import { Mosaic } from "@fungi.computer/caps/blocks/mosaic";
function swatch(color: string): string {
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80"><rect width="80" height="80" fill="${color}"/><circle cx="40" cy="40" r="22" fill="white" opacity="0.5"/></svg>`;
return `data:image/svg+xml,${encodeURIComponent(svg)}`;
}
const items = [
{ id: "a", alt: "Lion's Mane cluster", url: swatch("#8a6d3b") },
{ id: "b", alt: "Oyster shelf", url: swatch("#4b6b8a") },
{ id: "c", alt: "Chanterelle patch", url: swatch("#c98a2b") },
{ id: "d", alt: "Spore print", url: swatch("#5a7a4a") },
];
export default function Photos() {
return (
<Mosaic className="w-full max-w-sm" label="Recent finds" items={items} />
);
}

States

TSX
import { Mosaic, type MosaicItem } from "@fungi.computer/caps/blocks/mosaic";
import { useState } from "react";
const items: MosaicItem[] = [
{ id: "a", state: "ready", alt: "Chanterelle patch" },
{ id: "b", state: "loading", alt: "Uploading" },
{ id: "c", state: "error", alt: "Failed upload" },
{ id: "d", state: "ready", alt: "Oyster shelf", disabled: true },
];
export default function States() {
const [opened, setOpened] = useState<string | null>(null);
return (
<div className="flex flex-col gap-sm">
<Mosaic
className="w-full max-w-sm"
label="Uploads"
items={items}
onOpen={(item) => {
setOpened(item.id);
}}
/>
<p className="text-sm">Opened: {opened ?? "none"}</p>
</div>
);
}

Props

MosaicProps

PropTypeDescription
empty?ReactNode
itemsreadonly MosaicItem[]
label?ReactNodeCaller-owned accessible copy for the list.
onOpen()?(item) => voidWhen absent, tiles are deliberately non-interactive.
  • empty?ReactNode
  • itemsreadonly MosaicItem[]
  • label?ReactNode

    Caller-owned accessible copy for the list.

  • onOpen()?(item) => void

    When absent, tiles are deliberately non-interactive.

Full types: API reference.