Component API
Everything here is exported from @rd/designer. The element class is ReportDesigner, and the tag is report-designer
(HTMLElementTagNameMap is augmented, so document.querySelector('report-designer') is typed).
Attributes#
Attributes are strings, so use them in HTML. Each one also has a property of the same meaning.
| Attribute | Property | Type | Default | Description |
|---|---|---|---|---|
font-base-url | fontBaseUrl | URL string | ./fonts/ next to the script | Folder that holds the fonts' manifest.json (@rd/fonts) and, optionally, manifest-cjk.json (@rd/fonts-cjk). Set it whenever a bundler includes the designer (Install) |
help-base-url | helpBaseUrl | URL string | '' (built-in guide) | Optional override. When set, the Help drawer shows the external copy of the user guide at this URL in an iframe (for example the render service's /help/) instead of the built-in one |
help | help | "false" / boolean | true | help="false" hides the Help button and disables F1 |
theme | theme | 'light' | 'dark' | 'auto' | 'light' | Color theme (reflected). auto follows the operating system's light or dark mode, live. THEMES lists the values |
read-only | readOnly | boolean | false | View-only: no edits, palette and editing commands disabled (reflected) |
lang | lang | string | '' (browser language) | UI language: en, es, fr, de, pt-BR, zh-CN, zh-TW, ja, ko, or any BCP-47 tag (mapped to the nearest) |
builtin-gallery | builtinGallery | "false" / boolean | true | builtin-gallery="false" hides the 20 built-in gallery templates |
Properties (objects)#
Set these from JavaScript, never as attributes.
| Property | Type | Default | Description |
|---|---|---|---|
template | Template | null | null (blank Letter page) | The design. Setting it replaces the design and clears undo history, unless it is deep-equal to the current design (then it is ignored, which makes two-way binding safe). Loading a template never fires template-change |
schema | object | null | null | JSON Schema of your data contract. Drives the Fields tab (Data contracts and JSON Schema) |
gallery | GalleryEntry[] | [] | Host-supplied gallery entries, listed before the built-ins (Templates and gallery) |
Read-only properties:
| Property | Type | Description |
|---|---|---|
uiLanguage | string | The UI language in effect after resolution and fallback, e.g. 'de' |
renderInWorker | boolean | true when previews render in a Web Worker, false for the main-thread fallback |
Note: The element also exposes a
storeproperty, the internal editor state. It is not a supported API and may change in any release.
Methods#
| Method | Returns | Description |
|---|---|---|
getTemplate() | Template | A deep copy of the current design |
setTemplate(template) | void | Same as setting template. null gives a blank Letter page |
setSchema(schema) | void | Same as setting schema |
renderPdf() | Promise<RenderResult> | Renders the current design in placeholder mode (preview text, no data): { pdf: Uint8Array, pageCount, warnings, license }. Every page carries a light "PREVIEW" watermark: final documents come from the render API (License) |
openHelp(topic?, context?) | boolean | Opens context help. topic is a key of HELP_TOPICS; without it, the topic follows the current selection or open dialog. Fires help-request first. Returns false when help is disabled or the host cancelled the event |
closeHelp() | void | Closes the help drawer |
Events#
All events bubble and are composed, so they cross shadow boundaries.
| Event | detail type | When |
|---|---|---|
template-change | TemplateChangeDetail = { template: Template } | 300 ms after the last user edit (debounced). Not fired when the host loads a template. Toolbar New, Open template JSON and gallery picks count as edits |
save | TemplateChangeDetail | The user pressed Ctrl/Cmd+S or clicked Save. A final template-change is dispatched immediately before it |
help-request | HelpRequestDetail = { topic: HelpTopic; url: string } | Help was requested (Help button, F1 or openHelp()). url is the relative page and anchor in the user guide (07-tables.html#table-settings), or an absolute URL under help-base-url when that override is set. Cancelable: call preventDefault() to show help your own way (Language, help and read-only mode) |
Typed listeners:
import type { HelpRequestDetail, ReportDesigner, TemplateChangeDetail } from '@rd/designer';
const designer = document.querySelector('report-designer') as ReportDesigner;
designer.addEventListener('template-change', (e) => {
const { template } = (e as CustomEvent<TemplateChangeDetail>).detail;
console.log('edited:', template.name);
});
designer.addEventListener('save', (e) => {
void saveTemplate('bol', (e as CustomEvent<TemplateChangeDetail>).detail.template);
});
designer.addEventListener('help-request', (e) => {
const { topic, url } = (e as CustomEvent<HelpRequestDetail>).detail;
console.log('help for', topic, 'at', url);
});
Slots#
| Slot | Default | Description |
|---|---|---|
logo | The Report Designer icon | Your own icon at the left of the toolbar: an <img> or <svg> child with slot="logo", fitted into 26 × 26 px (Styling) |
<report-designer font-base-url="/rd-fonts/">
<img slot="logo" src="/assets/brand-mark.svg" alt="" />
</report-designer>
With mountDesigner, add it to the element it returns:
const logo = Object.assign(document.createElement('img'), { src: '/assets/brand-mark.svg', alt: '' });
logo.slot = 'logo';
handle.element.append(logo);
mountDesigner(container, options)#
Creates a <report-designer> inside container (give the container a height) and returns a handle.
interface MountOptions {
template?: Template | null;
schema?: object | null;
fontBaseUrl?: string;
helpBaseUrl?: string; // optional: show an external copy of the guide instead of the built-in one
help?: boolean; // false hides help
theme?: 'light' | 'dark' | 'auto';
lang?: string;
gallery?: GalleryEntry[];
builtinGallery?: boolean; // false hides the built-in templates
readOnly?: boolean;
onChange?: (template: Template) => void; // debounced 300 ms after edits
onSave?: (template: Template) => void; // Ctrl/Cmd+S or Save
}
interface DesignerHandle {
element: ReportDesigner;
getTemplate(): Template;
setTemplate(template: Template | null): void;
setSchema(schema: object | null): void;
openHelp(topic?: string): boolean;
setLang(lang: string): void; // switches the UI language live
renderPdf(): Promise<RenderResult>;
destroy(): void; // removes the element and its listeners
}
Exported types and values#
| Export | Kind | Description |
|---|---|---|
ReportDesigner | class | The element class |
mountDesigner, MountOptions, DesignerHandle | function, types | Imperative API |
TemplateChangeDetail, HelpRequestDetail | types | Event details |
GalleryEntry | type | Host gallery entry (Templates and gallery) |
JsonSchema | type | The subset of JSON Schema the Fields tab reads |
HELP_TOPICS, HelpTopic | const, type | Help topic keys mapped to user-guide pages ('element.table' → 07-tables.html#table-settings) |
LANGS, LANG_NAMES, resolveLang, Lang | const, function, type | Supported UI languages, their native names, and tag resolution (resolveLang('es-MX') → 'es') |
createBlankTemplate, validateTemplate | functions | Re-exported from @rd/core |
Template, RenderResult, RenderOptions, ValidationIssue, RenderLicense, … | types | All @rd/core types are re-exported |
Building a language picker with the exported values:
import { LANGS, LANG_NAMES, resolveLang, type ReportDesigner } from '@rd/designer';
const designer = document.querySelector('report-designer') as ReportDesigner;
const select = document.createElement('select');
for (const lang of LANGS) {
select.add(new Option(LANG_NAMES[lang], lang, false, lang === resolveLang(navigator.language)));
}
select.addEventListener('change', () => (designer.lang = select.value));
document.body.prepend(select);
Validating a template before storing it, in the browser or in Node:
import { validateTemplate, type Template } from '@rd/designer';
function assertValid(template: Template): void {
const errors = validateTemplate(template).filter((i) => i.severity === 'error');
if (errors.length) {
throw new Error(errors.map((i) => `${i.path}: ${i.message}`).join('\n'));
}
}
Keyboard handling and focus#
The element sets tabindex="0" (unless you set one) and handles its shortcuts (Ctrl/Cmd+Z, Ctrl/Cmd+S, Delete, arrows, F1 …) only while focus is inside it, so it
doesn't steal shortcuts from the rest of your page. Ctrl/Cmd+S calls preventDefault() so the browser's "Save page" dialog doesn't open.