Tiling
Editable tile layouts with dragging, resizing, and serializable positions.
Components in this category
Cell grid whose tiles the reader can drag, resize and rearrange.
MosaicTileOne tile of a MosaicGrid, with its drag and resize grips.
MosaicGripDrag control for a custom tile header.
MosaicShowRenders its children only while the enclosing tile is big enough.
The idea
MosaicGrid and MosaicTile provide editable layouts represented by { id, x, y, w, h } entries. Persist the array to save layout preferences.
MosaicGrid controls geometry, collisions, gravity, and input handling. MosaicTile renders a tile and its grips. Tiles accept arbitrary content.
MosaicGrid positions tiles on a cell grid. Tile content is supplied by the application.
A layout that builds itself
findFreeSlot places added tiles in the first available cell in reading order. The grid positions tiles from a layout array. useMosaicLayout provides layout updates and history.
Persisting an arrangement
Pass restored layouts through normalizeLayout. It clamps entries to the current column count and resolves placement. This prevents entries saved for a wider grid from rendering outside the new grid.
const mosaic = useMosaicLayout({ defaultLayout: DEFAULT_LAYOUT });
// Restore — normalised, so an old or foreign layout cannot draw off-grid.
useEffect(() => {
const saved = localStorage.getItem("board:on-call");
if (saved) mosaic.restore(JSON.parse(saved));
}, []);
// Save — onLayoutChange fires once per gesture, not per frame.
<MosaicGrid
{...mosaic.gridProps}
editable={editing}
onLayoutChange={(next) => {
mosaic.setLayout(next);
localStorage.setItem("board:on-call", JSON.stringify(next));
}}
/>;