creating-docs-examples

star 21.9k

Use when creating code examples for documentation pages - JavaScript, TypeScript, React, Angular, and Vue variants with proper imports, registration, and license key

handsontable By handsontable schedule Updated 6/5/2026

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

Creating Documentation Code Examples

This skill covers how to write runnable code examples that are embedded in documentation guide pages.

File Structure

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">`)

Key Rules

  • 25-60 lines per example. Keep examples focused and scannable.
  • One concept per example. Use progressive numbering for complexity: example1 = basic setup, example2 = a configuration variation, example3 = advanced usage.
  • TypeScript is primary. Always write the .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.
  • Use realistic data. Prefer createSpreadsheetData() or domain-appropriate sample data (product names, dates, currencies). Avoid trivial arrays like [1, 2, 3].

Required Elements in Every Example

  1. 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().

  2. License key - always include:

    licenseKey: 'non-commercial-and-evaluation'
    
  3. Container element - target the conventional #example div:

    const container = document.querySelector('#example');
    

Framework-Specific Patterns

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:

  • All components must be standalone (standalone: true, imports: [HotTableModule]).
  • Use app.config.ts (not app.module.ts) with ApplicationConfig, provideZoneChangeDetection({ eventCoalescing: true }), and global HOT_GLOBAL_CONFIG for the license key.
  • Do not add licenseKey to individual <hot-table> bindings -- it is set globally in app.config.ts.
  • Template control flow: use @if / @for (x of list; track x.id) -- never *ngIf / *ngFor.
  • Name the component class 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:

  • Never use 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: ['...'].
  • Never use 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.
  • Never inject services via the constructor. Use inject() instead. JIT mode lacks TypeScript decorator metadata, so constructor DI throws NG0202.
  • Never bind Handsontable hooks in the template ((afterInit)="handler()"). Put hook functions inside gridSettings instead.
  • Only import symbols you actually use. Unused imports (e.g., 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).

  • Do: one exampleN.vue file per example, with <script setup lang="ts">.
  • Do not: use plain <script setup> without lang="ts".
  • Do not: split logic into exampleN.js + exampleN.html (legacy pattern). When you touch an old split example, migrate it to a .vue SFC.
  • Do not: use the Options API (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:

  • Always use <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.
  • Call registerAllModules() once at the top level of <script setup> (not inside onMounted).
  • Import HotTable and HotColumn from @handsontable/vue3. Register them by using them in <template> (no global app.component() registration).
  • Put licenseKey: 'non-commercial-and-evaluation' inside the settings object passed to HotTable.
  • The root <div> in <template> must use an id that matches the example container in the guide (#example1 in ::: example #example1 :vue3).
  • Prefer a single :settings object for grid options. Use individual props only when the guide text highlights a specific prop.
  • Put Handsontable hooks (afterChange, beforeDataProviderFetch, etc.) inside the settings object, not as Vue event listeners on <HotTable>.
  • Use 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).
  • Always use useTemplateRef('refName') for template refs bound via ref="..." in <template>. Never use ref() for template refs.
  • HotTable instance access:
import { useTemplateRef } from 'vue';

const hotRef = useTemplateRef<InstanceType<typeof HotTable>>('hotRef');
<HotTable ref="hotRef" :settings="hotSettings" />

Access: hotRef.value?.hotInstance.

  • DOM element refs:
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.

  • For HotColumn, nest it inside <HotTable> in <template> and pass column options via :settings on each HotColumn.
  • Optional <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).

Embedding in the Guide

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.

Checklist

  • TypeScript source written and tested (.ts/.tsx, or Vue .vue with lang="ts").
  • JS variant generated for JavaScript/React examples (not hand-written). Vue examples have no JS variant.
  • licenseKey: 'non-commercial-and-evaluation' present.
  • Imports use handsontable/base + registration pattern.
  • Example stays within 25-60 lines.
  • One concept per example with realistic data.
  • Vue examples use .vue SFC with <script setup lang="ts"> and Composition API (no split .js/.html, no Options API).
Install via CLI
npx skills add https://github.com/handsontable/handsontable --skill creating-docs-examples
Repository Details
star Stars 21,922
call_split Forks 3,188
navigation Branch main
article Path SKILL.md
More from Creator
handsontable
handsontable Explore all skills →