demo-page

star 21.9k

Use when creating a demo or test page for manual testing of Handsontable. Trigger when the user asks to create a demo, test page, repro page, reproduction case, manual test, or wants to verify a bug fix or feature visually. Also trigger when the user mentions dev-generated.html, dev-pr.html, dev-latest.html, dev.html, or wants to compare behavior between a released version and a local build. Use this for any PR that needs a manual testing artifact.

handsontable By handsontable schedule Updated 5/13/2026

name: demo-page description: Use when creating a demo or test page for manual testing of Handsontable. Trigger when the user asks to create a demo, test page, repro page, reproduction case, manual test, or wants to verify a bug fix or feature visually. Also trigger when the user mentions dev-generated.html, dev-pr.html, dev-latest.html, dev.html, or wants to compare behavior between a released version and a local build. Use this for any PR that needs a manual testing artifact.

Demo Page Generator

Generate two self-contained HTML demo pages for manual testing:

File Loads from Purpose
handsontable/dev-latest.html jsDelivr CDN (latest published version) Shows the current/buggy behavior
handsontable/dev-pr.html Local dist/ (built from the branch) Shows the fix or new feature

Both files are gitignored (dev*.html pattern), so they never pollute the repo.

Each file links to the other at the top, so a reviewer can switch back and forth without losing scroll position or state context. Two separate files means complete JS/CSS isolation — no dual-instance loading tricks, no stylesheet toggling, no shared globals between versions.

Step 1 — Analyze the PR context

Before generating the demo, understand what needs testing. Read the relevant source changes to determine:

  • What bug is being fixed, or what feature is being added?
  • Which plugins, editors, cell types, or settings are involved?
  • What user interaction reproduces the issue (click, double-click, keyboard, scroll, touch)?
  • Are there specific data shapes needed (merged cells, nested headers, large datasets)?

Use git log and git diff against the base branch to understand the changes. If there's a linked GitHub issue, read it for reproduction steps.

Step 2 — Build Handsontable

Always run the build unconditionally — do not check whether dist/ exists first:

npm run build --prefix handsontable

Step 3 — Generate the two demo files

Write both files using the templates below. Both are gitignored (dev*.html), so they never pollute the repo.

Files already exist? Both files are throwaway — generated by a previous task. Skip reading them. Wipe them first, then write fresh:

rm -f handsontable/dev-pr.html handsontable/dev-latest.html

Then use the Write tool to create each file from scratch.

Each file is a standalone single-instance page. The nav bar at the top links to the other file — the current file's link is styled as active (non-clickable) so the reviewer always knows where they are.

Template — handsontable/dev-latest.html (Released / CDN)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>[short description] — Released v__RELEASED_VERSION__</title>
  <link rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/handsontable@__RELEASED_VERSION__/styles/ht-theme-main.min.css">
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 16px; background: #f5f5f5; }
    h1 { font-size: 18px; margin-bottom: 12px; }
    nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; }
    .nav-label { font-size: 13px; color: #666; margin-right: 4px; }
    .nav-btn {
      padding: 6px 16px; border-radius: 6px; font-size: 14px; text-decoration: none;
      border: 1px solid #ccc;
    }
    .nav-btn.active { background: #fff; font-weight: 600; border-color: #999; color: #111; pointer-events: none; }
    .nav-btn:not(.active) { background: #e9e9e9; color: #333; }
    .nav-btn:not(.active):hover { background: #f0f0f0; }
    .badge { display: inline-block; font-size: 11px; padding: 1px 7px; border-radius: 10px; margin-left: 6px; vertical-align: middle; }
    .badge-cdn { background: #e3f2fd; color: #1565c0; }
    .badge-local { background: #e8f5e9; color: #2e7d32; }
    .info { background: #fff3cd; border: 1px solid #ffc107; border-radius: 6px; padding: 12px 16px; margin-bottom: 16px; font-size: 14px; line-height: 1.5; }
    .info strong { color: #856404; }
  </style>
</head>
<body>
  <h1>[Short description of what is being tested]</h1>

  <nav>
    <span class="nav-label">Version:</span>
    <span class="nav-btn active">Released <span class="badge badge-cdn">v__RELEASED_VERSION__</span></span>
    <a class="nav-btn" href="dev-pr.html">PR Build <span class="badge badge-local">local</span></a>
  </nav>

  <div class="info">
    <strong>How to test:</strong> [Step-by-step reproduction instructions]
  </div>

  <div id="hot-container"></div>

  <script src="https://cdn.jsdelivr.net/npm/handsontable@__RELEASED_VERSION__/dist/handsontable.full.min.js"></script>
  <script>
    // window.hot is exposed for browser console / DevTools debugging
    window.hot = new Handsontable(document.getElementById('hot-container'), {
      // === ADAPT THIS CONFIG TO THE TEST CASE ===
      data: Handsontable.helper.createSpreadsheetData(10, 6),
      colHeaders: true,
      rowHeaders: true,
      width: '100%',
      height: 320,
      themeName: 'ht-theme-main',
      licenseKey: 'non-commercial-and-evaluation',
    });
  </script>
</body>
</html>

Template — handsontable/dev-pr.html (PR Build / local)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>[short description] — PR Build</title>
  <link rel="stylesheet" href="styles/ht-theme-main.css">
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 16px; background: #f5f5f5; }
    h1 { font-size: 18px; margin-bottom: 12px; }
    nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; }
    .nav-label { font-size: 13px; color: #666; margin-right: 4px; }
    .nav-btn {
      padding: 6px 16px; border-radius: 6px; font-size: 14px; text-decoration: none;
      border: 1px solid #ccc;
    }
    .nav-btn.active { background: #fff; font-weight: 600; border-color: #999; color: #111; pointer-events: none; }
    .nav-btn:not(.active) { background: #e9e9e9; color: #333; }
    .nav-btn:not(.active):hover { background: #f0f0f0; }
    .badge { display: inline-block; font-size: 11px; padding: 1px 7px; border-radius: 10px; margin-left: 6px; vertical-align: middle; }
    .badge-cdn { background: #e3f2fd; color: #1565c0; }
    .badge-local { background: #e8f5e9; color: #2e7d32; }
    .info { background: #fff3cd; border: 1px solid #ffc107; border-radius: 6px; padding: 12px 16px; margin-bottom: 16px; font-size: 14px; line-height: 1.5; }
    .info strong { color: #856404; }
  </style>
</head>
<body>
  <h1>[Short description of what is being tested]</h1>

  <nav>
    <span class="nav-label">Version:</span>
    <a class="nav-btn" href="dev-latest.html">Released <span class="badge badge-cdn">v__RELEASED_VERSION__</span></a>
    <span class="nav-btn active">PR Build <span class="badge badge-local">local</span></span>
  </nav>

  <div class="info">
    <strong>How to test:</strong> [Step-by-step reproduction instructions]
  </div>

  <div id="hot-container"></div>

  <script src="dist/handsontable.full.js"></script>
  <script>
    // window.hot is exposed for browser console / DevTools debugging
    window.hot = new Handsontable(document.getElementById('hot-container'), {
      // === ADAPT THIS CONFIG TO THE TEST CASE ===
      data: Handsontable.helper.createSpreadsheetData(10, 6),
      colHeaders: true,
      rowHeaders: true,
      width: '100%',
      height: 320,
      themeName: 'ht-theme-main',
      licenseKey: 'non-commercial-and-evaluation',
    });
  </script>
</body>
</html>

Filling in the templates

Replace these placeholders in both files:

Placeholder Value
__RELEASED_VERSION__ The latest published version from handsontable/package.json (e.g., 17.0.1). If the PR branch bumped the version, use the version from the base branch (git show origin/develop:handsontable/package.json).
[Short description...] A one-line summary, e.g., "Filters dropdown closes on Android touch"
[Step-by-step reproduction...] Numbered steps the reviewer should follow, e.g., "1. Double-tap cell A1. 2. The editor should open and stay open."

Keep the <script> config identical in both files — the only difference between the pages is which Handsontable build they load. That way any behavioral difference the reviewer sees is caused by the code change, not a config discrepancy.

Adapting the config

Tailor the Handsontable config block based on what the PR changes:

Bug fix PRs — Configure the grid to reproduce the bug. dev-latest.html should exhibit the broken behavior; dev-pr.html should show it fixed. Include the minimal settings needed to trigger the issue.

Feature PRs — Configure the grid to showcase the new feature. dev-latest.html shows the "before" state (feature absent); dev-pr.html demonstrates the new capability.

Plugin-specific — Enable the relevant plugin with settings that exercise the changed code paths. Example for Filters:

window.hot = new Handsontable(document.getElementById('hot-container'), {
  data: Handsontable.helper.createSpreadsheetData(20, 6),
  colHeaders: true,
  rowHeaders: true,
  dropdownMenu: true,
  filters: true,
  width: '100%',
  height: 400,
  themeName: 'ht-theme-main',
  licenseKey: 'non-commercial-and-evaluation',
})

Touch/mobile testing — Keep the grid width responsive (width: '100%'). Mention touch-specific steps in the instructions.

Third-party integrations — If the demo needs external libraries (flatpickr, Pickr, etc.), load them from CDN in both files. Keep versions consistent.

Additional CSS and external libraries

Add them to the <head> of both files:

<!-- Example: flatpickr for date editor testing -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>

Step 4 — Serve and verify

Start a local server from the handsontable/ directory:

python3 -m http.server 8767 --directory handsontable &

Verify both files are reachable:

curl -s -o /dev/null -w "dev-latest: %{http_code}\n" http://localhost:8767/dev-latest.html && \
curl -s -o /dev/null -w "dev-pr:     %{http_code}\n" http://localhost:8767/dev-pr.html

Tell the user both URLs:

  • http://localhost:8767/dev-latest.html — Released version (CDN)
  • http://localhost:8767/dev-pr.html — PR Build (local)

The nav bar in each file links to the other, so the reviewer can switch back and forth without re-typing URLs.

Important notes

  • Both files are gitignored (dev*.html) — they will not appear in git status or get committed.
  • Each file loads only one Handsontable build — no dual-instance tricks needed.
  • If the released version used the old CSS system (pre-v17, dist/handsontable.full.css), adjust the CDN CSS link in dev-latest.html accordingly.
  • For very old version comparisons, check that the API used in the config block exists in both versions.
Install via CLI
npx skills add https://github.com/handsontable/handsontable --skill demo-page
Repository Details
star Stars 21,935
call_split Forks 3,190
navigation Branch main
article Path SKILL.md
More from Creator
handsontable
handsontable Explore all skills →