DocMosaicdocs
Examples

Template gallery

A starter-templates dialog wired to localStorage for "recently used".

Editor.TemplateGallery is the modal grid you show when a user starts blank. Pass it an array of Document snapshots and clicking one swaps the live document in a single undoable step. Pair it with localStorage to remember which templates a user has opened recently.

Code

'use client';

import { useMemo, useState } from 'react';
import { Editor, type TemplateGalleryItem } from '@docmosaic/react';
import { createDocument, createPage, type Document } from '@docmosaic/core';
import '@docmosaic/react/styles.css';

// Static templates ship with the app - keep these checked in.
const STATIC_TEMPLATES: ReadonlyArray<TemplateGalleryItem> = [
    {
        id: 'blank',
        name: 'Blank A4',
        document: createDocument({ name: 'Untitled', pageSize: 'A4', orientation: 'portrait' }),
    },
    {
        id: 'letter',
        name: 'US Letter',
        document: createDocument({ name: 'Untitled', pageSize: 'LETTER', orientation: 'portrait' }),
    },
    {
        id: 'landscape-a4',
        name: 'A4 landscape',
        document: createDocument({ name: 'Untitled', pageSize: 'A4', orientation: 'landscape' }),
    },
    {
        id: 'three-pager',
        name: 'Three pages',
        document: {
            ...createDocument({ name: 'Three-pager', pageSize: 'A4', orientation: 'portrait' }),
            pages: [createPage(), createPage(), createPage()],
            totalPages: 3,
        } as Document,
    },
];

function rememberRecent(id: string) {
    if (typeof window === 'undefined') return;
    const prev = JSON.parse(localStorage.getItem('recent-templates') ?? '[]') as string[];
    const next = [id, ...prev.filter((p) => p !== id)].slice(0, 5);
    localStorage.setItem('recent-templates', JSON.stringify(next));
}

export default function TemplatesEditor() {
    const [open, setOpen] = useState(true);
    const templates = useMemo(() => STATIC_TEMPLATES, []);

    return (
        <Editor.Root>
            {open ? (
                <div className="fixed inset-0 z-10 flex items-center justify-center bg-black/40 p-8">
                    <div className="max-w-3xl rounded-lg bg-white p-6 shadow-xl">
                        <h2 className="mb-4 text-lg font-semibold">Pick a template</h2>
                        <Editor.TemplateGallery
                            templates={templates}
                            onTemplateSelected={(t) => {
                                rememberRecent(t.id);
                                setOpen(false);
                            }}
                        />
                    </div>
                </div>
            ) : null}

            <Editor.Properties />
            <Editor.Toolbar />
            <Editor.Pages />
            <Editor.Canvas>
                <Editor.Section />
            </Editor.Canvas>
        </Editor.Root>
    );
}

onTemplateSelected fires after the document swap. Use it for analytics, dialog close, or - like here - bumping the template id to the front of a recents list.

The swap goes through actions.loadDocument, which is captured by the history timeline in uncontrolled mode. Users can mod+z back to the previous document.

Try it

On this page