This document describes how to put Typograph on a page: what to load, where it mounts, and what a host container has to provide. It is intended for developers embedding Typograph into an existing application rather than serving it as a page of its own.
There are two products and two bundles. The editor (editor.js) authors
templates: full chrome, menus, parameter bar, every tool. The viewer
(viewer.js) fills templates in: no chrome, a floating toolbar, and only the
edits the template permits. Everything below about mounting, containers and
lifecycle applies to both — where they differ is called out.
For tailoring the interface once it is running, see API-EditorUI.md.
Two scripts. The colour engine is a bare-global script and stays the host's job; everything else — the chrome, the stylesheet, the webfont — the bundle brings itself.
<script type="text/javascript" src="https://cdn.typograph.nl/editor/latest/scripts/jsColorEngineWeb.js"></script>
<script type="module" src="https://cdn.typograph.nl/editor/latest/editor.js"></script>
For the viewer, load viewer.js in place of editor.js. The colour engine is
the same and is still yours to load.
There is no markup to author. Earlier versions required a page to reproduce 31 specific element ids; that is no longer true, and any page still carrying that markup keeps working — the bundle detects it and leaves it alone.
The same applies to the stylesheet and the webfont: if your page already links
stylesheets/style.css or Source Sans Pro, the bundle detects those by href and
does not add a second copy. A page built against the older instructions, which
carried both <link> tags itself, keeps using its own — including a customised
stylesheet.
Load the two scripts and you are done. The editor mounts on document.body and
fills the viewport.
<!DOCTYPE html>
<html translate="no">
<head>
<meta charset="utf-8">
<script type="text/javascript" src=".../scripts/jsColorEngineWeb.js"></script>
<script type="module" src=".../editor.js"></script>
</head>
<body></body>
</html>
Construct a Typograph.Editor and give it a container. The chrome is built
inside that box instead of taking over the page.
<div id="app"></div>
<script type="module">
import { Editor } from 'https://cdn.typograph.nl/editor/latest/editor.js';
const editor = new Editor({ container: '#app' });
</script>
Editor is also available as window.Typograph.Editor if you would rather not
use a module script:
<script>
// After editor.js has loaded.
const editor = new Typograph.Editor({ container: '#app' });
</script>
containerA CSS selector, a bare element id, or an HTMLElement. All three work:
new Editor({ container: '#app' }); // selector
new Editor({ container: 'app' }); // bare id
new Editor({ container: document.getElementById('app') }); // element
If nothing matches, a warning is logged and the editor mounts on
document.body rather than failing silently.
Omit container entirely and you get the full-page editor.
This is the one requirement. The editor's layout is absolutely positioned
and resolves against the container's box, so a container with no height gives
you an editor with no height. A plain <div id="app"></div> collapses to zero.
Give it a definite size any way you like:
#app { position: absolute; top: 44px; left: 24px; right: 24px; bottom: 24px; }
#app { height: 90vh; }
/* Inside a flex or grid parent that gives it a track. */
#app { min-height: 0; }
The editor takes care of the rest: if the container is not already a positioned
box it is given position: relative, and if its overflow is visible it is given
overflow: hidden so nothing escapes the box you allotted. Both are restored on
destroy().
Your container keeps its own id and its own CSS. Inside the page, the editor adds
exactly one child element to your container, plus the two <link> tags in
<head> described above. Nothing else on the page is touched.
Menus, dialogs, colour pickers and the floating tool palettes are all confined to the box you gave the editor — none of them can be drawn over the rest of your page. A dialog that would be "centred on screen" in the full-page editor is centred in your container instead.
The one consequence worth knowing: a container much smaller than the editor's natural layout will clip its own overlays rather than let them escape. The chrome assumes roughly the room a desktop application gets.
The editor reserves 57px above the menu bar for a host's logo. If your application already has its own header, you will not want it:
new Editor({ container: '#app', header_space: false }); // remove it
new Editor({ container: '#app', header_space: 80 }); // or set your own height
Everything below moves with it. Omit the option and the layout is exactly what it has always been.
Construct the Editor before the window load event. Construct it later and the
editor will already have mounted itself on document.body under the full-page
defaults; container is then ignored and a warning says so. A module script in
the page body, as above, is early enough.
<div id="app"></div>
<script type="module">
import { Viewer } from 'https://cdn.typograph.nl/editor/latest/viewer.js';
const viewer = new Viewer({ container: '#app' });
</script>
Also available as window.Typograph.Viewer. Everything above applies unchanged:
the same container forms, the same height requirement, the same containment,
the same get_document() and destroy().
One difference in behaviour. The editor mounts itself when nothing constructs
it, so a page that only loads editor.js still gets an editor — history the
viewer does not have. viewer.js does nothing until you construct a Viewer.
Not the editor with things switched off. Canvas answers permission questions
differently in viewer mode: an element with no authored edit_options falls back
to a default that allows text editing and image content edits — moving, scaling
and rotating the image inside its frame — and refuses moving, resizing or
rotating the frames themselves. Grant those in a template and the same code
allows them, with no change to your host.
The toolbar floats and follows the selection, showing the controls for whatever is selected and undo/redo when nothing is. Drag it by its handle and it stays where you put it — following the selection is a convenience, your placement is an instruction.
new Viewer({
container: '#app',
show_rulers: true, // default true
page_bar: {
visible: true, // the bar itself
show_name: true, // each page's name
show_page_number: true, // the number badge
show_add_page: true, // the "new page" control
},
});
All are optional; omit any and canvas's own default applies.
page_bar matters more than it looks. The page bar is the viewer's only
navigation, but a filled-in template is not an authoring surface — the names it
carries are the template author's, not your user's, and there may be nothing to
number. Turn off what your product should not show.
show_add_page also settles an older rule: canvas suppressed the control in
viewer mode whenever a page was visible. Saying nothing keeps that. Setting it
either way makes your answer the whole answer.
No menu bar, content bar or parameter bar; no path tool, marquee, guides or multi-select. These are absent by construction, not hidden — a template cannot turn them on. Numeric position and size entry is the parameter bar's job and is therefore absent too; direct manipulation is the whole interface.
Replacing an image has no picker. React to the selection event and swap the image through the manifest API — the choice of what replaces it belongs to your application, not to Typograph.
No Find and Replace dialog either: it is a menu item, and there is no menu bar to
carry it. The API behind it is canvas-level rather than part of the editor's
chrome, so it works here unchanged — window.typograph.find() and
replace_all() are available in a viewer embed, and a host that needs to fill
placeholders, run a search or offer its own control can call them directly. See
FindReplace.md. If the filling in happens on your server before
the document reaches the viewer, TextModel.md is the same job
done there.
const editor = new Editor({ container: '#app' });
editor.get_document(); // the canvas document, once booted
editor.destroy(); // remove the editor's DOM and styles
Viewer has the same two:
const viewer = new Viewer({ container: '#app' });
viewer.get_document();
viewer.destroy();
get_document()Returns the canvas TypographDocument — the same object as
window.typograph.get_typograph_document(). Available once the editor has
booted; wait for typograph_editor_ready if you are unsure.
document.addEventListener('typograph_editor_ready', () => {
const doc = editor.get_document();
});
destroy()Removes the chrome and the injected stylesheet, and restores anything the editor wrote on your container. Your own content inside the container is left untouched.
Mounting a new editor afterwards is not supported. The canvas document has no
teardown entry point yet, so its state would survive a second boot. Constructing
another Editor after destroy() logs a warning and does nothing; reload the
page instead. Use destroy() to release the DOM when your view is torn down,
not as half of a mount/unmount cycle.
Constructing a second Editor destroys the first, and so does a second Viewer.
The two are separate bundles and do not know about each other, so do not load
both against the same page expecting them to cooperate — pick one. Two editors side by side
would need the canvas library's single global document undone, which is
deliberately deferred — see
ASSESSMENT-editor-viewer-canvas-architecture.md §3.4 in the canvas repository.
Icons, cursors, the stylesheet and its images all resolve against editor.js's
own URL, not the page embedding it. Loading the bundle from the CDN pulls its
assets from the CDN too, with nothing to configure — you can embed the editor
from a page on any origin.
This is why editor.js is shipped as an ES module and must be loaded with
type="module": the resolution uses import.meta.url, which does not exist in a
classic script.
Language data defaults to https://cdn.typograph.nl/languages, which works from
any host. Override RichTextEditor.languageAssetBaseUrl only if you are
self-hosting it.