con un clic
creating-docs-examples
Use when creating code examples for documentation pages - JavaScript, TypeScript, React, Angular, and Vue variants with proper imports, registration, and license key
Menú
Use when creating code examples for documentation pages - JavaScript, TypeScript, React, Angular, and Vue variants with proper imports, registration, and license key
| name | creating-docs-examples |
| path | docs/** |
| description | Use when creating code examples for documentation pages - JavaScript, TypeScript, React, Angular, and Vue variants with proper imports, registration, and license key |
This skill covers how to write runnable code examples that are embedded in documentation guide pages.
Each guide has framework-specific subdirectories for its examples:
docs/content/guides/category/feature/
feature.md # The guide page
javascript/ # JS examples
example1.js # Generated from TS - do not edit directly
example1.ts # Primary source - edit this first
react/ # React variants
example1.jsx # Generated from TSX
example1.tsx # Primary source
angular/ # Angular variants
example1.ts
example1.html # Template file
vue/ # Vue 3 variants
example1.vue # TypeScript SFC (`<script setup lang="ts">`)
example1 = basic setup, example2 = a configuration variation, example3 = advanced usage..ts / .tsx file first for JavaScript and React examples. From docs/, generate the JS variant with: npm run docs:code-examples:generate-js -- <path-to-ts-file> (path relative to docs/). Never hand-edit generated JS files. For Vue, write TypeScript inside the .vue file with <script setup lang="ts"> — there is no separate JS variant to generate.createSpreadsheetData() or domain-appropriate sample data (product names, dates, currencies). Avoid trivial arrays like [1, 2, 3].Imports - use the base import and explicit registration:
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
registerAllModules();
For examples that demonstrate tree-shaking, import individual plugins and cell types instead of registerAllModules().
License key - always include:
licenseKey: 'non-commercial-and-evaluation'
Container element - target the conventional #example div:
const container = document.querySelector('#example');
React (TSX/JSX):
import { HotTable } from '@handsontable/react-wrapper';
import { registerAllModules } from 'handsontable/registry';
registerAllModules();
const App = () => {
return <HotTable data={data} licenseKey="non-commercial-and-evaluation" />;
};
Angular:
standalone: true, imports: [HotTableModule]).app.config.ts (not app.module.ts) with ApplicationConfig, provideZoneChangeDetection({ eventCoalescing: true }), and global HOT_GLOBAL_CONFIG for the license key.licenseKey to individual <hot-table> bindings -- it is set globally in app.config.ts.@if / @for (x of list; track x.id) -- never *ngIf / *ngFor.AppComponent in every example.Critical Angular JIT restrictions — the docs site bootstraps Angular examples with JIT in the browser. JIT cannot load external files at runtime:
styleUrls in standalone components. CSS is injected globally by the example-runner via the --css slot. If you need component-scoped styles, use inline styles: ['...'].templateUrl. Always define the component's template inline with template: \...`. The angular/example1.html` file is the outer wrapper (selector tag) consumed by the example-runner -- it is not the component's template.inject() instead. JIT mode lacks TypeScript decorator metadata, so constructor DI throws NG0202.(afterInit)="handler()"). Put hook functions inside gridSettings instead.RowObject, ViewChild, NgFor) can cause module resolution errors.The .ts file contains both app.component.ts and app.config.ts as separate /* file: ... */ sections within a single file:
/* file: app.component.ts */
import { Component } from '@angular/core';
import { GridSettings, HotTableModule } from '@handsontable/angular-wrapper';
@Component({
standalone: true,
imports: [HotTableModule],
selector: 'example1-feature-name',
template: `
<div>
<hot-table [data]="data" [settings]="gridSettings"></hot-table>
</div>
`,
})
export class AppComponent {
readonly data = [...];
readonly gridSettings: GridSettings = { ... };
}
/* end-file */
/* file: app.config.ts */
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { registerAllModules } from 'handsontable/registry';
import { HOT_GLOBAL_CONFIG, HotGlobalConfig, NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';
registerAllModules();
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
{ provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE } as HotGlobalConfig },
],
};
/* end-file */
The angular/example1.html file is the outer wrapper (not the component template):
<div>
<example1-feature-name></example1-feature-name>
</div>
Edit on StackBlitz: When you use Edit on StackBlitz, docs/public/example-tabs.js merges each framework's companion example*.html into the generated app shell. parseDocsExampleHtmlForStackBlitz uses the browser DOMParser to collect style nodes for <head> and drop script nodes from the body fragment. mergeCompanionHtmlForStackBlitz wires that into the StackBlitz template. Examples with no HTML tab keep the previous default mount markup.
See skill angular-wrapper-dev for the full reference.
Vue 3:
Write every new or updated Vue example as a TypeScript Single-File Component (.vue) using the Composition API and <script setup lang="ts">. The docs example-runner loads vue/example*.vue modules and mounts them with createApp() (see docs/src/scripts/example-runner.ts).
exampleN.vue file per example, with <script setup lang="ts">.<script setup> without lang="ts".exampleN.js + exampleN.html (legacy pattern). When you touch an old split example, migrate it to a .vue SFC.defineComponent with data(), methods, etc.) in new examples.SFC skeleton:
<script setup lang="ts">
import { ref } from 'vue';
import { HotTable } from '@handsontable/vue3';
import { registerAllModules } from 'handsontable/registry';
import type { GridSettings } from 'handsontable/settings';
registerAllModules();
const hotSettings = ref<GridSettings>({
data: [
['Acme Corp', 'Q1 2025', '$4.2M'],
['Vertex Industries', 'Q1 2025', '$18.7M'],
],
colHeaders: true,
height: 'auto',
licenseKey: 'non-commercial-and-evaluation',
});
</script>
<template>
<div id="example1">
<HotTable :settings="hotSettings" />
</div>
</template>
Vue-specific rules:
<script setup lang="ts">. Type grid options with GridSettings from handsontable/settings. Add local type aliases for row or domain data when the example uses object rows.registerAllModules() once at the top level of <script setup> (not inside onMounted).HotTable and HotColumn from @handsontable/vue3. Register them by using them in <template> (no global app.component() registration).licenseKey: 'non-commercial-and-evaluation' inside the settings object passed to HotTable.<div> in <template> must use an id that matches the example container in the guide (#example1 in ::: example #example1 :vue3).:settings object for grid options. Use individual props only when the guide text highlights a specific prop.afterChange, beforeDataProviderFetch, etc.) inside the settings object, not as Vue event listeners on <HotTable>.ref() from vue for reactive state that the template or handlers update (hotSettings, toggles, selected values). Use a plain const for hotSettings when reactive deep updates would trigger unwanted updateSettings() calls (for example, when only a status label changes beside the grid).useTemplateRef('refName') for template refs bound via ref="..." in <template>. Never use ref() for template refs.import { useTemplateRef } from 'vue';
const hotRef = useTemplateRef<InstanceType<typeof HotTable>>('hotRef');
<HotTable ref="hotRef" :settings="hotSettings" />
Access: hotRef.value?.hotInstance.
const dropdownRef = useTemplateRef<HTMLDivElement>('dropdownRef');
<div ref="dropdownRef" class="theme-dropdown">...</div>
Access: dropdownRef.value. The string passed to useTemplateRef(...) must match the template ref attribute exactly.
HotColumn, nest it inside <HotTable> in <template> and pass column options via :settings on each HotColumn.<style scoped> is allowed for example-only UI (buttons, status text). Example-runner CSS from the guide's --css slot still applies globally.Presets on the ::: example directive select dependencies: :vue3 (default), :vue3-languages, :vue3-vuex. Match the preset to the feature the page demonstrates.
Embedding a Vue SFC (single tab, no --html / --js):
::: example #example1 :vue3
@[code](@/content/guides/category/feature/vue/example1.vue)
:::
See skill vue-wrapper-dev for wrapper behavior (HotTable, HotColumn, settings propagation).
After creating example files, embed them in the guide's .md file using the @[code] directive inside an ::: example container. See the writing-docs-pages skill for the full embedding syntax.
.ts/.tsx, or Vue .vue with lang="ts").licenseKey: 'non-commercial-and-evaluation' present.handsontable/base + registration pattern..vue SFC with <script setup lang="ts"> and Composition API (no split .js/.html, no Options API).Use for ANY work touching the `handsontable/` core package: fixing bugs, adding features, modifying TypeScript types, removing as-casts, writing or debugging plugins, editors, renderers, validators, cell types, hooks, shortcuts, selection, helpers, index translations, or i18n. Also use for how-to questions about core internals (plugin lifecycle, coordinate systems, hook registration, TypeScript conventions). Triggers on file paths under `handsontable/src/` (excluding `3rdparty/walkontable/` which has its own skill), or when the user describes a symptom in the core grid without naming a file. This is the primary entry point for all core Handsontable development — when in doubt, load it.
Use when writing or modifying Jasmine/Puppeteer E2E tests (*.spec.js) for Handsontable, or when a bug fix or feature change needs E2E test coverage. Covers standard boilerplate, async/await rules, global helpers, event simulation, plugin lifecycle patterns, and writing theme-agnostic assertions that pass under all themes without branching on theme name.
Use when adding user-facing text to Handsontable, creating new language constants, updating translation files, or working with RTL layouts and internationalization
Use whenever you are about to create, push, open, update, or edit a pull request in the Handsontable monorepo — load this BEFORE running `gh pr create` or pushing a feature/docs/fix branch, not only when the user says "PR". Triggers: create/open/submit a PR, push the branch, commit and push, ship it, ready to review, update or fix a PR description, any PR URL, finishing work on a `feature/*`/`docs/*`/`fix/*` branch, or a completed ClickUp/DEV task ready to submit. Covers branch naming, pre-flight lint/tests, the PR-first then changelog flow, `gh auth` fallback, and filling the GitHub PR template.
Use when creating or modifying a Handsontable cell validator - async callback-based validation functions that determine if cell values are valid
Use when creating or editing documentation pages in docs/content/guides/ - covers YAML frontmatter, page structure, framework-specific example embedding, writing style, and sidebar registration