Record PDF Export
A three-step wizard (Select a Template → Preview → PDF) that renders a Docyrus data source record to PDF using its saved HTML templates, with an optional editable-template mode.
Record PDF Export turns a single Docyrus data source record into a PDF through a guided three-step wizard:
- Select a Template — lists the data source's saved HTML/PDF templates (
tenant_html_template). - Preview — renders the chosen template compiled against the record, using the
HtmlTemplateEditorin preview-only mode. - PDF — generates the final PDF server-side and shows it in an inline viewer with a download button.
- Email (optional, when
sendEmailis set) — mounts an email composer (useDocyrusEmailComposer) with the generated PDF pre-attached, so the user can send the record straight from the wizard.
The headless useDocyrusRecordPdfExport hook owns all data
fetching, step state, and PDF generation. DocyrusRecordPdfExportWizard is the batteries-included
UI built on top of it. The hook accepts a dataSourceId and recordId — the app / data
source slugs needed by the render endpoints are resolved automatically (or supplied explicitly).
This is a Docyrus-connection component. It needs an authenticated RestApiClient to
list templates, load the record, and render the PDF, so the preview above is informational only —
wire it against your tenant (or the playground) to see it live.
Installation
pnpm dlx @docyrus/cli add @docyrus/ui-record-pdf-exportpnpm add @tanstack/react-query @docyrus/api-clientUsage
Wizard inside a dialog
import { useState } from 'react';
import { useDocyrusAuth } from '@docyrus/signin';
import { DocyrusRecordPdfExportWizard } from '@docyrus/ui/components/record-pdf-export';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger
} from '@docyrus/ui/primitives/ui/dialog';
import { Button } from '@docyrus/ui/primitives/ui/button';
function ExportRecordButton({ dataSourceId, recordId }: { dataSourceId: string; recordId: string }) {
const { client } = useDocyrusAuth();
const [open, setOpen] = useState(false);
if (!client) return null;
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="outline">Export to PDF</Button>
</DialogTrigger>
<DialogContent className="max-w-4xl">
<DialogHeader>
<DialogTitle>Export record to PDF</DialogTitle>
</DialogHeader>
<DocyrusRecordPdfExportWizard
client={client}
dataSourceId={dataSourceId}
recordId={recordId}
onClose={() => setOpen(false)}
/>
</DialogContent>
</Dialog>
);
}Editable-template mode
Pass templateEditable to let the user tweak the rendered document before exporting. The preview
step then exposes the Code, Data (read-only reference), and Preview tabs — the Code tab
holds the server-compiled document HTML for this record. When it is edited, the PDF step renders the
edited HTML through the custom-body endpoint instead of the saved template.
<DocyrusRecordPdfExportWizard
client={client}
dataSourceId={dataSourceId}
recordId={recordId}
templateEditable
/>Email step
Pass sendEmail to append an Email step. After the PDF is generated, the wizard mounts an email
composer (via useDocyrusEmailComposer) with the
rendered PDF pre-attached (sent through its storage path) and the user's email accounts loaded into
the From selector. Sending requires the Messaging.Email.Send OAuth scope.
<DocyrusRecordPdfExportWizard
client={client}
dataSourceId={dataSourceId}
recordId={recordId}
sendEmail
/>Headless — drive your own UI
import { HtmlTemplateEditor } from '@docyrus/ui/components/html-template-editor';
import { useDocyrusRecordPdfExport } from '@docyrus/ui/components/record-pdf-export';
function CustomExport({ client, dataSourceId, recordId }) {
const {
step, goNext, goBack, canGoNext,
templates, selectedTemplateId, setSelectedTemplateId,
previewEditorProps,
pdfUrl, isGeneratingPdf
} = useDocyrusRecordPdfExport({ client, dataSourceId, recordId });
// Step 1 — render `templates` and call `setSelectedTemplateId(id)`.
// Step 2 — <HtmlTemplateEditor {...previewEditorProps} />
// Step 3 — <iframe src={pdfUrl} /> (auto-generated on entering the step).
}How it works
| Step | Endpoint(s) | Notes |
|---|---|---|
| Resolve slugs | GET /v1/dev/data-sources/:dataSourceId | Maps dataSourceId → app_slug + slug. Skipped when appSlug + dataSourceSlug are supplied. |
| List templates | GET /v1/dev/html-templates?tenantDataSourceId=:dataSourceId | Drives the "Select a Template" step. The default template (is_default) is auto-selected. |
| Compiled preview | GET /v1/apps/:appSlug/data-sources/:dataSourceSlug/items/:recordId/templates/:templateId/html | Returns the server-compiled document body (+ styles) for this record — the same templateCompiler the PDF uses. This is the preview source, so the preview matches the PDF exactly. |
| Record data (editable only) | GET /v1/apps/:appSlug/data-sources/:dataSourceSlug/items/:recordId?columns=* | Read-only reference shown in the editable-mode Data tab. |
| Render PDF (saved) | GET /v1/apps/:appSlug/data-sources/:dataSourceSlug/items/:recordId/templates/:templateId/pdf | Default path. The server compiles the saved template against the record. |
| Render PDF (edited) | PUT /v1/apps/:appSlug/data-sources/:dataSourceSlug/items/:recordId/renderPdfTemplate/:templateId | Used in templateEditable mode when the compiled HTML was edited. Sends the edited HTML as a multipart/form-data body file (data={} so the server loads the record for header/footer). |
All render endpoints require the bearer token to carry a DS.Read.{Slug} (or
DS.ReadWrite.{Slug}) scope for the target data source. The render result is
returned under the response data as { id, path, fullPath, url? }.
When the backend includes a signed/public url, the PDF step renders it inline with a
Download button; otherwise it shows a "generated" confirmation with the filename.
Preview uses the HTML Template Editor
The preview step mounts HtmlTemplateEditor with the
server-compiled document HTML as value, then restricts the visible tabs. Compiling on the
server (rather than client-compiling the raw template against the raw record) is what makes the
preview faithful — the record's fields are mapped/expanded exactly as they are for the PDF. Three
editor props power this:
| Prop | Type | Purpose |
|---|---|---|
visibleTabs | HtmlTemplateEditorTab[] | Restricts which tabs render (and their order). The wizard passes ['preview'] (read-only) or ['code', 'data', 'preview'] (editable). The tab strip auto-hides when a single tab remains, and the Visual/Plate tab is intentionally omitted (its round-trip is lossy for complex nested-block table templates). |
dataReadOnly | boolean | Makes only the Data tab read-only while keeping the Code editor editable — the record data is a reference, not editable. |
previewStyles | string | Extra CSS injected into the Preview iframe (the template's styles), without baking a <style> block into the Plate document tree. |
In editable mode the user tweaks the compiled document HTML (the final output for this record) in the Code tab — the custom-body PDF endpoint takes final HTML as-is, so this is the only round-trip-faithful editing surface the API supports.
Hook — useDocyrusRecordPdfExport
const wizard = useDocyrusRecordPdfExport(options);Options
| Option | Type | Default | Description |
|---|---|---|---|
client | RestApiClient | — | Authenticated REST client. |
dataSourceId | string | — | tenant_data_source.id of the record's data source. |
recordId | string | — | tenant_data_source_item.id of the record to render. |
appSlug | string | — | App slug. When omitted, resolved from dataSourceId. |
dataSourceSlug | string | — | Data source slug. When omitted, resolved from dataSourceId. |
enabled | boolean | true | Toggles all network activity. |
templateEditable | boolean | false | Exposes template + read-only Data tabs in the preview; edited bodies render via the custom-body endpoint. |
sendEmail | boolean | false | Appends an Email step that mounts a composer with the generated PDF pre-attached. Sending needs the Messaging.Email.Send scope. |
initialTemplateId | string | — | Pre-select a template by id. |
autoSelectDefaultTemplate | boolean | true | Auto-select the default (or first) template once the list resolves. |
resolveDataSourceEndpoint | string | /v1/dev/data-sources/{id} | Endpoint override for slug resolution. |
listTemplatesEndpoint | string | /v1/dev/html-templates | Endpoint override for the templates list. |
templateDetailEndpoint | string | /v1/dev/html-templates/{templateId} | Endpoint override for a template's body. |
Returns
| Field | Type | Description |
|---|---|---|
steps | RecordPdfExportStep[] | Ordered steps for this wizard — includes 'email' when sendEmail is set. |
step / setStep / stepIndex | RecordPdfExportStep … | Current step ('select' | 'preview' | 'pdf' | 'email') and controls. |
goNext / goBack / canGoNext / canGoBack / isLastStep | — | Step navigation. |
appSlug / dataSourceSlug / isResolving / resolveError | — | Resolved slugs + resolution state. |
templates / isLoadingTemplates / templatesError / refetchTemplates | — | Templates list state. |
selectedTemplateId / setSelectedTemplateId / selectedTemplate | — | Selected template. |
templateDetail / isLoadingTemplateDetail / templateDetailError | DocyrusHtmlTemplateDetail … | Selected template's body / styles. |
record / recordJson / isLoadingRecord / recordError | — | The target record (object + pretty JSON string). |
templateEditable / editedHtml / setEditedHtml / isDirty / resetEdits | — | Editable body state. |
generatePdf / isGeneratingPdf / pdfResult / pdfUrl / pdfError | — | PDF generation. Auto-fires on entering the PDF step. |
previewEditorProps | RecordPdfExportPreviewEditorProps | Ready to spread onto <HtmlTemplateEditor> for the preview step. |
reset | () => void | Reset the wizard back to the first step. |
API Reference — DocyrusRecordPdfExportWizard
Extends every hook option plus:
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Wrapper class. |
bodyHeight | string | '70vh' | Height of the wizard body region. |
onClose | () => void | — | Fired by the footer Done button on the PDF step. |
hideClose | boolean | false | Hide the footer Done button. |
Type Exports
| Type | Description |
|---|---|
UseDocyrusRecordPdfExportOptions | Options for the hook. |
UseDocyrusRecordPdfExportResult | Return shape of the hook. |
RecordPdfExportPreviewEditorProps | Props spread onto HtmlTemplateEditor for the preview. |
DocyrusRecordPdfExportWizardProps | Props for the wizard component. |
DocyrusHtmlTemplateSummary | Template list row. |
DocyrusHtmlTemplateDetail | Template detail row (adds body / styles). |
DocyrusRecordPdfResult | The upstream html-to-pdf result (url, filename, …). |
RecordPdfExportStep | 'select' | 'preview' | 'pdf'. |