Components

FillDoc

A page you can write on — headings, prose and sheets, on real A4.

A document, not a control. FillSheet is the table; this is the page it sits in. The two share a look on purpose — a real A4 sheet, real margins, square corners, and nothing drawn that is not content — and the same split between the person who makes a form and the person who fills it in.

Two modes, again

modethe prosethe sheetsthe page
editwritablefillable, resizableblocks can be added and removed
fillplain text, not a controlfillablefixed

In fill a heading renders as an <h2> and a paragraph as a <p> — not as a disabled textarea. A control sitting there that does nothing when clicked is worse than plain text.

Blocks

type FillDocBlock =
  | { id: string; type: "heading"; text: string }
  | { id: string; type: "text"; text: string }
  | { id: string; type: "table"; columns: FillSheetColumn[]; value: string[][] }

Every edit — typing, inserting, removing, filling a cell — comes back through onBlocksChange as the whole document. A table block's cell edit carries the other blocks through untouched, so the document is always one value you can store.

Nothing shows until you are there

A block draws no chrome at rest: no handle, no outline, no drag grip. The remove control appears in the margin beside the block the pointer is in, and the insert controls appear in the gap between two blocks. A page covered in controls stops looking like a page, which is the whole thing this is for.

Getting it out

import { docToHTML, docToMarkdown } from "@crisp-ui-kit/crisp";

docToHTML gives an HTML document body — headings, paragraphs and real <table>s — which is what Word, Google Docs and Pages read. A table block hands straight off to FillSheet's own writer, so there is one implementation of table escaping rather than two that drift. Prose is escaped, so a document cannot inject markup into its own export.

Installation

npm install @crisp-ui-kit/crisp

Props

Prop

Type

On this page