← Val TownCONTENT HISTORY

Update to Val Town

Snapshot Sep 30, 2026 · 22:50 UTC · version 3.0.0

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "name": "react-ui",
  "description": "Use when building any val with a user interface — dashboards, web apps, landing pages, forms, admin tools, anything users see in a browser. Covers JSX/React conventions, Twind/Tailwind styling, React version pinning, the view-source link requirement, and what to avoid (template-string HTML, external assets).",
  "included_files": [],
  "skill_md_contents": "---\nname: react-ui\ndescription: Use when building any val with a user interface — dashboards, web apps, landing pages, forms, admin tools, anything users see in a browser. Covers JSX/React conventions, Twind/Tailwind styling, React version pinning, the view-source link requirement, and what to avoid (template-string HTML, external assets).\n---\n\n# React UI\n\nFor any val that renders a UI, prefer to build it with React components in `.tsx` files, unless the user states otherwise. The `templates/react-hono-starter` template is set up for this — start there with `remix_val` instead of building from scratch.\n\n## File conventions\n\nPut markup, styles, and scripts in real files — avoid template literal strings (e.g. `new Response(\\`<html>...</html>\\`)`). Code in template strings has no syntax highlighting, no linting, no type checking, and is unreviewable.\n\n- `.tsx` — React/JSX components, any UI with logic or interactivity\n- `.html` — purely static markup\n- `.ts` — server code and scripts\n\nBuild UI **component by component** in `.tsx` files. Compose small components rather than rendering one giant page.\n\n## Styling: Twind + Tailwind\n\nPrefer Twind to apply Tailwind utility classes at runtime — no build step required. Add the script to your HTML shell:\n\n```html\n<script src=\"https://cdn.twind.style\" crossorigin></script>\n```\n\nThen use Tailwind classes directly in JSX:\n\n```tsx\n<div className=\"flex items-center gap-4 p-6 rounded-lg bg-white shadow\">\n  <h1 className=\"text-2xl font-bold\">Hello</h1>\n</div>\n```\n\nAvoid inline `<style>` tags, CSS-in-JS objects, or separate `.css` files, unless the user says otherwise.\n\n## Serving assets: versioned + immutable\n\nServe client modules with `serveImmutableFile` from `std/utils` — browsers cache\nthem immutably, and publishing bumps the val's version, which invalidates\nautomatically (full pattern: the `client-side-js` skill). A never-cached\n`frontend/root.tsx` shell (hono/jsx) stamps the entry and favicon with\n`immutableFileUrl`:\n\n```tsx\n// frontend/root.tsx — in the Root() HTML shell:\n<script src={immutableFileUrl(\"/frontend/index.tsx\")} type=\"module\" />\n\n// index.ts:\napp.get(\"/\", (c) => c.html(Root()));\napp.get(\"/__immutable/*\", (c) => serveImmutableFile(c.req.path));\n```\n\n## View source link\n\nEvery UI val should expose a way for users to see and remix its source. Both parts are required:\n\n1. Backend route:\n   ```ts\n   import { parseVal } from \"https://esm.town/v/std/utils/index.ts\";\n   app.get(\"/source\", (c) => c.redirect(parseVal().links.self.val));\n   ```\n2. Visible link in the frontend:\n   ```tsx\n   <a href=\"/source\">view source</a>\n   ```\n\n## React version pinning\n\nA common error — `\"Cannot read properties of null (reading 'useState')\"` — means a React sub-dependency is loading a different React version. Pin all React-related imports to 18.2.0:\n\n```ts\nimport SomeLib from \"https://esm.sh/some-lib?deps=react@18.2.0,react-dom@18.2.0\";\n```\n\n## Assets\n\nDo not use external images or hosted assets that may break. Prefer:\n\n- Emojis or unicode symbols\n- Inline SVG\n- Icon fonts via CDN (Lucide, Font Awesome)\n\n## Surfacing client-side errors\n\nTo send browser errors back to val logs (visible via `get_logs`), include this script in your HTML shell:\n\n```html\n<script src=\"https://esm.town/v/std/catch\"></script>\n```\n\n## Verifying changes\n\nAfter editing a UI val, call `fetch_val_endpoint` to confirm the page renders without error, then check `get_logs` for any client-side errors. Don't report the change as done without both.\n"
}

SHA-256: dd9c235c0f7ff8ae5f23318b29f4d3c835edf1a919e69e14679d85debc7bc9b9