@nativele/ts-dom 0.5.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -0
- package/README.md +6 -1
- package/README.zh-TW.md +6 -1
- package/dist/{a11y-CiEJj_e6.mjs → a11y-KXbo-8o3.mjs} +119 -27
- package/dist/cli.mjs +273 -50
- package/dist/{lint-Did4w-NL.mjs → lint-DUsdDKZ-.mjs} +33 -8
- package/dist/oxlint-plugin.mjs +3 -3
- package/dist/vite-plugin.mjs +1 -1
- package/docs/architecture.md +188 -0
- package/docs/components.md +367 -0
- package/docs/contributing.md +80 -0
- package/docs/design.md +55 -0
- package/docs/lists.md +150 -0
- package/docs/performance.md +24 -0
- package/docs/recipes.md +189 -0
- package/docs/templates.md +73 -0
- package/docs/tooling.md +251 -0
- package/llms.txt +5 -5
- package/package.json +2 -1
- package/skills/README.md +51 -14
- package/skills/nativele-angular/SKILL.md +15 -11
- package/skills/nativele-architecture/SKILL.md +29 -16
- package/skills/nativele-ci/SKILL.md +148 -0
- package/skills/nativele-core/SKILL.md +16 -13
- package/skills/nativele-formatting/SKILL.md +167 -0
- package/skills/nativele-integration/SKILL.md +12 -9
- package/skills/nativele-linting/SKILL.md +174 -0
- package/skills/nativele-monorepo/SKILL.md +298 -0
- package/skills/nativele-react/SKILL.md +13 -10
- package/skills/nativele-state-management/SKILL.md +6 -6
- package/skills/nativele-svelte/SKILL.md +10 -8
- package/skills/nativele-tailwind/SKILL.md +8 -7
- package/skills/nativele-tanstack-query/SKILL.md +5 -5
- package/skills/nativele-testing/SKILL.md +22 -16
- package/skills/nativele-typescript/SKILL.md +186 -0
- package/skills/nativele-vite/SKILL.md +21 -17
- package/skills/nativele-vue/SKILL.md +10 -8
- package/skills/nativele-zod/SKILL.md +6 -6
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nativele-typescript
|
|
3
|
+
description: "Check and adjust the TypeScript set-up of a project that uses Nativele (@nativele/ts-dom): what the tsconfig covering the components needs and why, which stricter options and layouts work, how the generated files and ts-dom check fit the type check. Use when a tsconfig is added or changed, when ts-dom doctor reports a tsconfig-* issue, or when tsc errors point at the set-up rather than the code."
|
|
4
|
+
metadata:
|
|
5
|
+
tier: official
|
|
6
|
+
nativele: ">=0.6.0 <0.7.0"
|
|
7
|
+
verified: "2026-11-06"
|
|
8
|
+
tools: "typescript@7.0.2 typescript@6.0.3 typescript@5.9.3 vue-tsc@3.3.14 @tsconfig/strictest@2.0.8"
|
|
9
|
+
author: "Nativele maintainers"
|
|
10
|
+
detects: "typescript"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Nativele + TypeScript
|
|
14
|
+
|
|
15
|
+
## When to use
|
|
16
|
+
|
|
17
|
+
- The project depends on `@nativele/ts-dom` and `typescript`, and you set up, review or change a `tsconfig*.json`, or `ts-dom doctor` reports `no-tsconfig`, `tsconfig-not-strict`, `tsconfig-no-dom-lib`, `tsconfig-classic-resolution`, `tsconfig-misses-templates` or `tsconfig-misses-tag-map`.
|
|
18
|
+
- `tsc` or `ts-dom check` fails with errors that come from the set-up (module not found, DOM names missing, a component typed as `HTMLElement`) rather than from a component.
|
|
19
|
+
- This Skill owns `tsconfig*.json` as far as Nativele is concerned. It does not write components (`nativele-core`), the build or its scripts (`nativele-vite`, or the framework's Skill), lint configuration (`nativele-linting`), formatter configuration (`nativele-formatting`), CI (`nativele-ci`), or a framework's own type checker (`vue-tsc`, `svelte-check`, `ngc`); it states what those need from TypeScript and leaves the how to them.
|
|
20
|
+
|
|
21
|
+
Nativele's value is that `tsc` checks the HTML against the TypeScript: `ts-dom gen` writes a typed `x.html.ts` next to each template and a `ts-dom-tags.ts` per scanned folder, and the tsconfig decides whether `tsc` sees them. Nativele needs no special TypeScript option: it needs a few ordinary ones to be in place, and works with the common stricter ones.
|
|
22
|
+
|
|
23
|
+
## Versions
|
|
24
|
+
|
|
25
|
+
| Tool | Verified version |
|
|
26
|
+
|---|---|
|
|
27
|
+
| @nativele/ts-dom | 0.6.0 (the last agent trial) |
|
|
28
|
+
| typescript | 7.0.2, 6.0.3, 5.9.3 (every row below); 5.6.3, 5.4.5, 5.0.4 (the baseline set-up only) |
|
|
29
|
+
| vue-tsc | 3.3.14 (with typescript 6.0.3 and 7.0.2) |
|
|
30
|
+
| @tsconfig/strictest | 2.0.8 |
|
|
31
|
+
|
|
32
|
+
Verified on 2026-11-06 in fresh projects built from the packed library, with a fixture of components that covers state, props, derive, emits with and without detail, keyed lists of components, plain lists, slots, `shadow: true`, `bind`, `on`, `instantiate()` and the tag map, plus probe files whose `// @ts-expect-error` lines must each stay an error. With a TypeScript major version not listed, treat every statement as unverified.
|
|
33
|
+
|
|
34
|
+
## Set-up
|
|
35
|
+
|
|
36
|
+
Check first, then change only what fails. Never replace a tsconfig, reorder it, or change an option this Skill does not name.
|
|
37
|
+
|
|
38
|
+
1. **Find the config that type-checks the components.** Read `tsconfig.json` in the folder where `ts-dom` runs (the one with `package.json`). If it has `"files": []` and `references` (a solution-style root, as in Vite's templates), the configs that count are the referenced ones; find the one whose `include` covers the Nativele folder (in Vite's templates, `tsconfig.app.json`). Leave the other configs (for `vite.config.ts`, Node scripts, tests in another runtime) as they are.
|
|
39
|
+
2. **Read its effective options, not the file.** `npx tsc --showConfig -p <config>` prints the options after every `extends` (a relative path, a package such as `@tsconfig/strictest`, or an array) and the file list. It does not print defaults: an absent `strict` is on in TypeScript 6 and 7 and off in TypeScript 5 (see Known limitations). `npx tsc --listFilesOnly -p <config>` lists every file in the program; after `npx ts-dom gen <dir>`, each `x.html.ts` and the folder's `ts-dom-tags.ts` must be in it.
|
|
40
|
+
3. **Run `npx ts-dom doctor <dir>`** (the same folders you pass to `ts-dom check`). Each `tsconfig-*` issue names the file and the fix. Doctor reads `tsconfig.json` and its references only, and checks the referenced configs that cover the template folders; for a config that is not `tsconfig.json`, pass `--project=<path>`.
|
|
41
|
+
4. **Compare with what Nativele needs**, and change only the rows that fail:
|
|
42
|
+
|
|
43
|
+
| Requirement | Why | Without it (exact error) |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `lib` includes `DOM` (or `lib` absent: the default includes it) | the library's types and the generated files name DOM types | `node_modules/@nativele/ts-dom/dist/index.d.mts(3,24): error TS2304: Cannot find name 'Element'.` (with `skipLibCheck: true`: `TS2584: Cannot find name 'document'` and `TS2304: Cannot find name 'Event'` in your files); doctor: `tsconfig-no-dom-lib` |
|
|
46
|
+
| A module resolution that finds packages in `node_modules`: `bundler` (with `module` `ESNext` or `Preserve`), `NodeNext`, or `Node16` (`node10` too, on TypeScript 5 only) | the components and the generated files import `@nativele/ts-dom` | with `classic` on TypeScript 5: `TS2792: Cannot find module '@nativele/ts-dom'`, and then every component loses its base class (`TS2339: Property 'refs' does not exist on type 'X'`); TypeScript 6 rejects `classic` and `node10` with `TS5107` (deprecated), TypeScript 7 with `TS5108` (removed) |
|
|
47
|
+
| `include` covers the `.ts` files of every folder with templates | the generated `ts-dom-tags.ts` is imported by nothing, so only `include` brings it in; a component no other file imports is not checked at all | a component typed as plain `HTMLElement` (`TS2339: Property 'todo' does not exist on type 'HTMLElement'`), a keyed list reported as `item-not-in-tag-map`, and contract errors of unimported components (`missing-binding`) not reported; doctor: `tsconfig-misses-templates`, and `tsconfig-misses-tag-map` (an error) when `include` or `exclude` leaves `ts-dom-tags.ts` out |
|
|
48
|
+
| `strict: true` (set explicitly) | null checks and implicit `any` belong to it | see "What `strict` adds" below; doctor: `tsconfig-not-strict` (a warning) for `"strict": false`, and for an absent `strict` on TypeScript 5 |
|
|
49
|
+
| `"type": "module"` in `package.json`, when `module` is `NodeNext` or `Node16` and `tsc` emits the JavaScript | without it the files are CommonJS | `tsc` reports nothing, but emits `Object.defineProperty(exports, "__esModule", ...)`, which a browser cannot run; with `bundler`, or when `tsc` does not emit, it makes no difference to the type check |
|
|
50
|
+
|
|
51
|
+
Add a missing `DOM` to the existing `lib` array; add the missing folder to the existing `include` (as `"src/nv"` or a pattern ending in `.ts`, matching the style already there); change `moduleResolution` only when it is `classic`, absent with `module` `ESNext` on TypeScript 5 (that default is `classic`), or `node10`/`node` on TypeScript 6 or 7 (on 5.9.3 it works; leave it unless the user moves to a newer TypeScript).
|
|
52
|
+
5. **`strict`.** If it is absent, add `"strict": true`: on TypeScript 6 and 7 that changes nothing but makes it explicit for doctor and for TypeScript 5. If the project sets `"strict": false`, do not turn it on for the whole app on your own: the errors it brings in code outside the Nativele folder are not this task. Turn it on in the config that covers the Nativele folder, or, when that config is the whole app, add a config for the folder and pass it to `ts-dom check --project=` and `ts-dom doctor --project=`:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
// tsconfig.nv.json
|
|
56
|
+
{ "extends": "./tsconfig.json", "compilerOptions": { "strict": true }, "include": ["src/nv"] }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Tell the user that `ts-dom doctor` without `--project=` keeps warning `tsconfig-not-strict` on `tsconfig.json` in that case.
|
|
60
|
+
6. **Keep the user's other options.** The stricter options in the Compatibility table work with the generated files and the library's types; do not remove or relax one to make Nativele pass. The only option that does not work is `isolatedDeclarations` (Known limitations).
|
|
61
|
+
7. **State the order to the owner of the scripts.** The generated files are not committed, so every type check (`tsc`, `tsc -b`, `vue-tsc`, `svelte-check`, `ngc`, in a script, a hook or CI) must run after `ts-dom gen <dir>`, or be `ts-dom check <dir>`, which generates first. On a clean checkout a type check that runs first fails with `TS2307: Cannot find module './x.html.js' or its corresponding type declarations`, and doctor reports the script as `typecheck-before-gen`. Do not choose the script here: the build Skill (`nativele-vite`) or the framework's Skill owns it, and the CI steps belong to `nativele-ci`.
|
|
62
|
+
8. **Run Verify.**
|
|
63
|
+
|
|
64
|
+
### What `strict` adds
|
|
65
|
+
|
|
66
|
+
The template contract does not depend on `strict`: with `"strict": false` on 7.0.2, 6.0.3 and 5.9.3, `tsc` and `ts-dom check` still report `missing-binding`, `missing-handler` (from `define()`), an unknown `this.refs.x`, an unknown `this.show()` name, a child prop of the wrong type through `ts-dom-tags.ts`, a wrong `EmitEvent` detail type, `emit` with a missing, extra or undeclared event, writes to deeply read-only state, and a `data-prop` that is not a prop of the item component. What `strict` adds is everything about `null`, `undefined` and `any`: `'x' is possibly 'null'` (`TS18047`) from `querySelector`, `null` assigned to a prop or passed to `set()`, `hit.key` of an untyped `EventHit` used as a `PropertyKey` although it may be `undefined`, and `Parameter 'e' implicitly has an 'any' type` (`TS7006`). With `"strict": false` plus `"strictNullChecks": true` and `"noImplicitAny": true`, every one of those is reported again, but doctor still warns, because it reads only `strict`.
|
|
67
|
+
|
|
68
|
+
### Compatibility
|
|
69
|
+
|
|
70
|
+
Each option set on the config that covers the fixture, on 7.0.2, 6.0.3 and 5.9.3 (`tsc --noEmit`, and `ts-dom check`):
|
|
71
|
+
|
|
72
|
+
| Option | Result |
|
|
73
|
+
|---|---|
|
|
74
|
+
| `noUncheckedIndexedAccess` | works |
|
|
75
|
+
| `exactOptionalPropertyTypes` | works; `set({ x: undefined })` becomes an error, as for any `Partial` |
|
|
76
|
+
| `verbatimModuleSyntax` (with `NodeNext`, and with `bundler`) | works; emitting with `tsc` keeps the generated imports correct |
|
|
77
|
+
| `isolatedModules` | works |
|
|
78
|
+
| `erasableSyntaxOnly` | works |
|
|
79
|
+
| `noImplicitOverride` | works; your own `connected`, `render`, `slotchange` need `override`, as the guides write them |
|
|
80
|
+
| `noUnusedLocals`, `noUnusedParameters` | works, including generated files for templates without refs or with several root elements; name unused handler parameters `_e`, `_hit` |
|
|
81
|
+
| `noPropertyAccessFromIndexSignature`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, `noUncheckedSideEffectImports` | works |
|
|
82
|
+
| `allowImportingTsExtensions` | works; still import templates as `./x.html.js` (Known limitations) |
|
|
83
|
+
| `skipLibCheck` `true` or `false` | both work; `false` also checks the library's own declarations, which pass |
|
|
84
|
+
| all of the above together, and `extends: ["@tsconfig/strictest/tsconfig.json", ...]` | works |
|
|
85
|
+
| `declaration` or `composite` (with `emitDeclarationOnly`, `rootDir`, `outDir`) | works; `ts-dom check` on a `composite` config passes too |
|
|
86
|
+
| `isolatedDeclarations` | does not work (Known limitations) |
|
|
87
|
+
| `moduleResolution` `bundler`, `NodeNext`, `Node16`; `module` `CommonJS` or `Preserve` with the default resolution | works |
|
|
88
|
+
| `moduleResolution` `classic` | does not work: see step 4 |
|
|
89
|
+
| `moduleResolution` `node10` (or `node`) | works on 5.9.3; rejected by TypeScript 6 (`TS5107`) and 7 (`TS5108`) |
|
|
90
|
+
| `lib` / `target` `ES2015` or `ES2017` with `DOM` | works; `target` `ES5` is rejected by TypeScript 7 itself (`TS5108`) |
|
|
91
|
+
|
|
92
|
+
### How `ts-dom check` and `ts-dom doctor` choose configs
|
|
93
|
+
|
|
94
|
+
| | `ts-dom check [dirs]` | `ts-dom doctor [dirs]` |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| Default | `tsconfig.json` in the working folder; a solution-style one (`"files": []` with `references`) is replaced by each referenced config, and `tsc --noEmit -p <config>` runs once per config | `tsconfig.json` and, when solution-style, its references; the option checks run on the configs whose `include` covers a template folder, or on all of them when none does |
|
|
97
|
+
| Another config | `--project=<path>` | `--project=<path>` |
|
|
98
|
+
| Checker | `vue-tsc` when `package.json` lists it, otherwise `typescript`'s `tsc` | does not type-check |
|
|
99
|
+
| No config | `tsc-failed` (an error) | `no-tsconfig` (an error) |
|
|
100
|
+
|
|
101
|
+
A `ts-dom check` whose config does not cover the Nativele folder still runs and can pass with the components unchecked: on a `tsconfig.json` that includes only Node scripts, it reported only the lint findings, not the `missing-binding` the same run with `--project=` found. Doctor reports that layout as `tsconfig-misses-templates`.
|
|
102
|
+
|
|
103
|
+
### Framework type checkers
|
|
104
|
+
|
|
105
|
+
This Skill decides what the tsconfig that covers the Nativele folder needs (the table in step 4); that applies unchanged when the checker is `vue-tsc`, `svelte-check` or `ngc`, which read the same tsconfig. The framework's Skill decides which checker runs, its script, its own config (`vueCompilerOptions`, Svelte or Angular options) and the declarations that type Nativele tags in the framework's templates. What this Skill states to them:
|
|
106
|
+
|
|
107
|
+
- They need the generated files first, as in step 7.
|
|
108
|
+
- At the versions below they need TypeScript 6: `vue-tsc@3.3.14` with `typescript@7.0.2` stops with `Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './lib/tsc' is not defined by "exports"` (and `ts-dom check` reports that as `tsc-failed`); `svelte-check@4.7.8` declares the peer range `typescript@"^5.0.0 || ^6.0.0"` and npm refuses `typescript@7.0.2` with `ERESOLVE`; `@angular/compiler-cli@22.2.4` declares `typescript: '>=6.0 <6.1'`. The requirements in step 4 are the same on 6.0.3.
|
|
109
|
+
- `ts-dom check` runs `vue-tsc` itself when `package.json` lists it (verified: it reported a `TS2322` inside an `.vue` file); it does not run `svelte-check` or `ngc`.
|
|
110
|
+
|
|
111
|
+
## Example
|
|
112
|
+
|
|
113
|
+
A Vite app with a solution-style root, the Nativele components in `src/nv`, and a strict preset through `extends`. Before:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
// tsconfig.json
|
|
117
|
+
{ "files": [], "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }] }
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
// tsconfig.app.json
|
|
122
|
+
{
|
|
123
|
+
"extends": ["@tsconfig/strictest/tsconfig.json"],
|
|
124
|
+
"compilerOptions": {
|
|
125
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
126
|
+
"target": "ES2022",
|
|
127
|
+
"module": "ESNext",
|
|
128
|
+
"moduleResolution": "bundler",
|
|
129
|
+
"verbatimModuleSyntax": true,
|
|
130
|
+
"noEmit": true
|
|
131
|
+
},
|
|
132
|
+
"include": ["src"]
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`tsconfig.node.json` covers only `vite.config.ts` and has `"lib": ["ES2023"]`.
|
|
137
|
+
|
|
138
|
+
Checking it: the configs that count are the references, and `tsconfig.app.json` is the one whose `include` (`src`) covers `src/nv`. `npx tsc --showConfig -p tsconfig.app.json` shows `"strict": true` (from the preset) and `"moduleResolution": "bundler"`, and no `lib`, so the default for the target applies, which includes DOM. `npx ts-dom doctor src/nv` reports no `tsconfig-*` issue; it does not judge `tsconfig.node.json`, which covers no template folder, so its `"lib": ["ES2023"]` stays. Nothing in the tsconfigs changes. The one requirement left goes to the owner of the build script: `"build": "tsc -b && vite build"` type-checks before anything generates, and doctor reports it as `typecheck-before-gen` (the `.gitignore` lists `*.html.ts`); the Vite Skill or the framework's Skill decides how the script changes.
|
|
139
|
+
|
|
140
|
+
Verified with that layout: `npx ts-dom check src/nv` prints `ts-dom check: no issues`, `npx tsc -b` exits 0, and `npx tsc --listFilesOnly -p tsconfig.app.json` lists every `x.html.ts` and `src/nv/ts-dom-tags.ts`.
|
|
141
|
+
|
|
142
|
+
## Known limitations
|
|
143
|
+
|
|
144
|
+
1. **`strict` absent means different things.** TypeScript 6 and 7 turn `strict` on when the key is absent; TypeScript 5 leaves it off, so the same tsconfig loses the null checks on 5.9.3. `tsc --showConfig` does not show either default, and doctor warns `tsconfig-not-strict` for `"strict": false`, and for an absent `strict` only when the installed TypeScript is 5. Write `"strict": true`.
|
|
145
|
+
2. **A `classic` default on TypeScript 5.** `"module": "ESNext"` (any module from ES2015, or a `target` from ES2015 without `module`) without `moduleResolution` resolves as `classic` on TypeScript 5 (`tsc --showConfig` shows `"moduleResolution": "classic"`), and every import of `@nativele/ts-dom` fails with `TS2792`. Doctor reports `tsconfig-classic-resolution` for it when it finds TypeScript 5 installed; the fix is `bundler` or `NodeNext`.
|
|
146
|
+
3. **`include` and `exclude` can leave `ts-dom-tags.ts` out.** An `include` of `"src/nv/**/*.tsx"`, or an `exclude` of `**/ts-dom-tags.ts`, leaves it out of the program; doctor reports `tsconfig-misses-tag-map` (an error), and the symptoms are those of a missing `include` in step 4. Do not exclude the generated files from the config that covers the components, and let `include` select `.ts` files there. Excluding only `**/*.html.ts` is harmless (they are reached through imports) but has no purpose.
|
|
147
|
+
4. **Doctor starts from `tsconfig.json` unless told otherwise.** When that file is a plain config for something else (Node scripts, say) and another config covers the components, doctor reports `tsconfig-no-dom-lib` and `tsconfig-misses-templates` against `tsconfig.json`. Run `ts-dom doctor --project=<the other config>` with the same config as `ts-dom check --project=`, and do not add `DOM` or the component folder to a config that is not for them. A solution-style `tsconfig.json` (`"files": []` with `references` to both configs) makes the layout explicit; that renames what `tsc -p tsconfig.json` means, so it is the user's decision.
|
|
148
|
+
5. **`isolatedDeclarations` does not work** for the folder with components: every generated file fails with `TS9037: Default exports can't be inferred with --isolatedDeclarations.` and every component with `TS9021: Extends clause can't contain an expression with --isolatedDeclarations.` (`class X extends Component(tpl, ...)`). Keep it off in the config that covers the Nativele folder; a library package that needs it keeps its Nativele components in a package of their own (a workspace of several packages: `nativele-monorepo`).
|
|
149
|
+
6. **Template imports stay `./x.html.js`**, also with `allowImportingTsExtensions`. `import tpl from "./x.html.ts"` compiles, but the Nativele tools match `.html.js`: the template is reported as `no-importer`, and a `missing-binding` points at the `.ts` instead of the template line. With `allowImportingTsExtensions`, `tsc` requires `noEmit` or `emitDeclarationOnly`; `ts-dom check` always runs `tsc --noEmit`.
|
|
150
|
+
7. **Emitting with `tsc` on TypeScript 6 and 7** needs `rootDir` when `outDir` is set and the sources are in a subfolder: without it, `TS5011: The common source directory of 'tsconfig.json' is './src'. The 'rootDir' setting must be explicitly set`. TypeScript 5.9.3 emitted without it. This concerns projects without a bundler, where `tsc` writes the JavaScript.
|
|
151
|
+
8. **A plain `tsc` on a solution-style root checks nothing**: `npx tsc --noEmit` exited 0 with a broken component in `src/nv`; `tsc -b`, `tsc -p tsconfig.app.json` and `ts-dom check` reported it.
|
|
152
|
+
|
|
153
|
+
## Verify
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
npx tsc --showConfig -p <config> # expect: lib absent or with dom; moduleResolution bundler, nodenext or node16; strict true; the files include src/nv/ts-dom-tags.ts
|
|
157
|
+
npx ts-dom doctor src/nv # expect: no tsconfig-* issue (or only those Known limitations 4 explains; pass `--project=` for another config)
|
|
158
|
+
npx ts-dom check src/nv # expect: ts-dom check: no issues
|
|
159
|
+
npx tsc -b # with a solution-style root (or tsc --noEmit -p <config>); expect: exit code 0
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Then prove the check reaches the components: add `<p>{{ nope }}</p>` to a template of a component that has `state`, run `npx ts-dom check src/nv`, and expect `error [missing-binding] "nope" is used by {{ nope }} ...` at the template's line. If `strict` is on, also expect `const el = document.querySelector("x-y"); el.remove();` in a component file to give `TS18047: 'el' is possibly 'null'`. Remove both afterwards.
|
|
163
|
+
|
|
164
|
+
## Troubleshooting
|
|
165
|
+
|
|
166
|
+
| Symptom | Cause | Fix |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| `TS2307: Cannot find module './x.html.js' or its corresponding type declarations` | the generated files do not exist yet (clean checkout) | run `ts-dom gen <dir>` before the type check, or `ts-dom check <dir>` (step 7) |
|
|
169
|
+
| `TS2792: Cannot find module '@nativele/ts-dom'. Did you mean to set the 'moduleResolution' option to 'nodenext'` | `classic` resolution, written or the TypeScript 5 default for `module` `ESNext` | `"moduleResolution": "bundler"` (or `NodeNext`) |
|
|
170
|
+
| `TS5107: Option 'moduleResolution=node10' is deprecated` / `TS5108: ... has been removed` | TypeScript 6 / 7 with `node10` (or `node`) or `classic` | `bundler` or `NodeNext`; not `ignoreDeprecations` |
|
|
171
|
+
| `TS2304: Cannot find name 'Element'` in `node_modules/@nativele/ts-dom/dist/index.d.mts` | `lib` without `DOM` | add `"DOM"` to `lib` |
|
|
172
|
+
| `TS2339: Property '<prop>' does not exist on type 'HTMLElement'` on `document.createElement("x-y")`, or `item-not-in-tag-map` although `ts-dom gen` ran | `ts-dom-tags.ts` is not in the program: `include` misses the folder, selects only `.tsx`, or `exclude` drops it | fix `include`/`exclude`; confirm with `tsc --listFilesOnly -p <config>` |
|
|
173
|
+
| `ts-dom check: no issues` although a template is wrong | the config `ts-dom check` used does not cover the folder | `ts-dom doctor <dir>`; pass `--project=` or fix `include` |
|
|
174
|
+
| `TS2344: Type 'HTMLElementTagNameMap[K]' does not satisfy the constraint 'Element'` in `lib.dom.d.ts` | a follow-up of a component class broken by a contract error (`missing-binding`, ...); `ts-dom check` leaves it out in the class's own file and says in other files which error it follows from | fix the contract error that `ts-dom check` reports first |
|
|
175
|
+
| `tsc-failed`: `vue-tsc did not check the types: ... ERR_PACKAGE_PATH_NOT_EXPORTED ... './lib/tsc'` | `vue-tsc` with TypeScript 7 | TypeScript 6 in a Vue project; see the Vue Skill |
|
|
176
|
+
| `TS9037` / `TS9021` with `isolatedDeclarations` | Known limitations 5 | turn it off for the Nativele folder's config |
|
|
177
|
+
| `tsconfig-not-strict` | `"strict": false`, or `strict` absent on TypeScript 5 (on 6 and 7 an absent `strict` is on and not reported) | write `"strict": true` |
|
|
178
|
+
|
|
179
|
+
## See also
|
|
180
|
+
|
|
181
|
+
- Setup with TypeScript only, and the no-bundler tsconfig: https://github.com/Pixmi/nativele/blob/main/docs/tooling.md#installation-and-setup
|
|
182
|
+
- What each tool checks, `ts-dom check`, `ts-dom doctor` and which command writes files: https://github.com/Pixmi/nativele/blob/main/docs/tooling.md#checks
|
|
183
|
+
- The generated `x.html.ts` and why it is not committed: https://github.com/Pixmi/nativele/blob/main/docs/templates.md#how-types-are-generated
|
|
184
|
+
- `ts-dom-tags.ts` and element types across components: https://github.com/Pixmi/nativele/blob/main/docs/components.md#composition-using-multiple-components-together
|
|
185
|
+
- Several packages in a workspace, each with its own tsconfig: https://github.com/Pixmi/nativele/blob/main/skills/nativele-monorepo/SKILL.md
|
|
186
|
+
- How Skills share a project, and who owns which configuration: https://github.com/Pixmi/nativele/blob/main/skills/README.md#how-skills-work-together
|
|
@@ -3,8 +3,8 @@ name: nativele-vite
|
|
|
3
3
|
description: "Add Nativele to an existing Vite app without a UI framework, and set up the tsDom() Vite plugin correctly: dirs and Vite's root, multi-page apps, the build script, and what vite dev does when a template or component changes. Use when a project depends on vite (or vite-plus) and @nativele/ts-dom."
|
|
4
4
|
metadata:
|
|
5
5
|
tier: official
|
|
6
|
-
nativele: ">=0.
|
|
7
|
-
verified: "2026-11-
|
|
6
|
+
nativele: ">=0.6.0 <0.7.0"
|
|
7
|
+
verified: "2026-11-06"
|
|
8
8
|
tools: "vite@8.3.6 typescript@7.0.2 create-vite@9.3.4 vite-plus@1.5.0"
|
|
9
9
|
author: "Nativele maintainers"
|
|
10
10
|
detects: "vite vite-plus"
|
|
@@ -24,13 +24,13 @@ metadata:
|
|
|
24
24
|
|
|
25
25
|
| Tool | Verified version |
|
|
26
26
|
|---|---|
|
|
27
|
-
| @nativele/ts-dom | 0.
|
|
27
|
+
| @nativele/ts-dom | 0.6.0 (the last agent trial) |
|
|
28
28
|
| vite | 8.3.6 |
|
|
29
29
|
| typescript | 7.0.2 |
|
|
30
30
|
| create-vite (`vanilla-ts` template, the starting point) | 9.3.4 |
|
|
31
|
-
| vite-plus | 1.5.0 (checked by hand with `vp dev`, `vp build` and `vp lint
|
|
31
|
+
| vite-plus | 1.5.0 (checked by hand with `vp dev`, `vp build` and `vp lint`) |
|
|
32
32
|
|
|
33
|
-
Verified on 2026-11-
|
|
33
|
+
Verified on 2026-11-06 in Google Chrome 148 with the example project in the Nativele repository (`skills/nativele-vite/example`), and by an agent trial: a fresh agent did real work with only the Skill, and the result was checked independently. The example is a reference; it is not run in CI. With a different major version of Vite, treat every step as unverified.
|
|
34
34
|
|
|
35
35
|
## Set-up
|
|
36
36
|
|
|
@@ -38,7 +38,7 @@ Starting from the `vanilla-ts` template, which already has `"type": "module"`, a
|
|
|
38
38
|
|
|
39
39
|
1. `npm i @nativele/ts-dom`.
|
|
40
40
|
2. Keep the components in their own folder, for example `src/nv/`, each as `x.html` plus `x.ts` (write them with `nativele-core`).
|
|
41
|
-
3.
|
|
41
|
+
3. The `tsconfig.json` must meet Nativele's requirements; in this template only an explicit `"strict": true` is missing, and `"include": ["src"]` already covers `src/nv`. Check and adjust it with the TypeScript Skill (`npx ts-dom skills nativele-typescript`).
|
|
42
42
|
4. Create `vite.config.ts` (the template has none, so `ts-dom doctor` cannot report the plugin as missing yet):
|
|
43
43
|
|
|
44
44
|
```ts
|
|
@@ -48,7 +48,7 @@ Starting from the `vanilla-ts` template, which already has `"type": "module"`, a
|
|
|
48
48
|
export default defineConfig({ plugins: [tsDom({ dirs: ["src/nv"] })] });
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
`dirs` is resolved against Vite's `root`, not against the folder you run commands in (see step 8). The other options are in the setup guide.
|
|
51
|
+
`dirs` is resolved against Vite's `root`, not against the folder you run commands in (see step 8). The other options are in the setup guide. When the project has a formatter, the whitespace mode is decided by the formatting Skill (`npx ts-dom skills nativele-formatting`); give the plugin that mode (for `collapse`: `tsDom({ dirs: ["src/nv"], whitespace: "collapse" })`), and pass the same mode (`--whitespace=collapse`) to every `ts-dom gen` and `ts-dom check` in the scripts.
|
|
52
52
|
|
|
53
53
|
5. Replace `tsc` in the build script with `ts-dom check`, given the same folder:
|
|
54
54
|
|
|
@@ -56,26 +56,26 @@ Starting from the `vanilla-ts` template, which already has `"type": "module"`, a
|
|
|
56
56
|
npm pkg set scripts.build="ts-dom check src/nv && vite build"
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
The generated files are not committed, so on a clean checkout `tsc` runs before anything has written them and fails with `TS2307: Cannot find module './x.html.js'` and follow-on errors. `ts-dom check` writes them, then runs `tsc` and the lint rules. `vite build` writes them too, but it never type-checks.
|
|
59
|
+
The generated files are not committed, so on a clean checkout `tsc` runs before anything has written them and fails with `TS2307: Cannot find module './x.html.js'` and follow-on errors. `ts-dom check` writes them, then runs `tsc` and the lint rules. `vite build` writes them too, but it never type-checks. CI starts from such a checkout; the rest of what its job needs is in `npx ts-dom skills nativele-ci`.
|
|
60
60
|
|
|
61
61
|
6. Add `*.html.ts` and `ts-dom-tags.ts` to `.gitignore`.
|
|
62
62
|
7. Import each page's components from that page's entry module, and write the tags straight into the page's HTML (`<hello-card name="home"></hello-card>`; attributes reach string props). Import the component modules the way the project imports its own (`./nv/hello-card.ts` in this template), and templates always as `./x.html.js`.
|
|
63
|
-
8. When `root` is a sub-folder (a multi-page app or
|
|
63
|
+
8. When `root` is a sub-folder (a multi-page app, or an app kept in `web/` of the same package), each path is relative to a different folder (an app with its own `package.json` in a workspace is covered by `npx ts-dom skills nativele-monorepo` instead):
|
|
64
64
|
|
|
65
65
|
| Setting | Relative to | With `root: "web"` |
|
|
66
66
|
|---|---|---|
|
|
67
67
|
| `tsDom({ dirs })` | Vite's `root` | `["src/nv"]` |
|
|
68
68
|
| `ts-dom check`, `doctor`, `gen`, `lint` arguments | the folder they run in (the one with `package.json` and `tsconfig.json`) | `web/src/nv` |
|
|
69
|
-
| `include` in `tsconfig.json` | the tsconfig's folder | `["web/src"]` |
|
|
69
|
+
| `include` in `tsconfig.json` (owned by `nativele-typescript`) | the tsconfig's folder | `["web/src"]` |
|
|
70
70
|
| `build.rolldownOptions.input` | write absolute paths (see Troubleshooting) | `resolve(import.meta.dirname, "web/about.html")` |
|
|
71
71
|
|
|
72
72
|
Nativele needs nothing per page: each page's entry imports the components that page uses.
|
|
73
73
|
|
|
74
|
-
9. With Vite+ instead of Vite, import `defineConfig` from `"vite-plus"`; the plugin, `dirs` and the build script are the same
|
|
74
|
+
9. With Vite+ instead of Vite, import `defineConfig` from `"vite-plus"`; the plugin, `dirs` and the build script are the same. The `lint` block of the config belongs to the linting Skill (`npx ts-dom skills nativele-linting`). If `vp build` then stops with `Cannot find package 'vite'`, see Troubleshooting.
|
|
75
75
|
|
|
76
76
|
## Example
|
|
77
77
|
|
|
78
|
-
A two-page app with `root: "web"
|
|
78
|
+
A two-page app with `root: "web"`:
|
|
79
79
|
|
|
80
80
|
```
|
|
81
81
|
package.json tsconfig.json vite.config.ts
|
|
@@ -162,7 +162,7 @@ define("hello-card", HelloCard);
|
|
|
162
162
|
3. **Neither `vite dev` nor `vite build` type-checks.** Run `ts-dom check` (the build script in step 5 does), and run it after a template change that `vite dev` accepted without complaint.
|
|
163
163
|
4. **A wrong `dirs` fails without a warning from the plugin.** If `dirs` does not point at the templates from Vite's `root` (for example `["web/src/nv"]` with `root: "web"`), nothing is generated, and the first sign is an unresolved `./x.html.js` (see Troubleshooting).
|
|
164
164
|
5. **Pass one folder to every `ts-dom` command.** `ts-dom-tags.ts` is written into the folder a command is given, so `ts-dom check web` next to `ts-dom check web/src/nv` leaves a second `ts-dom-tags.ts` in `web/`; delete it and use the same folder everywhere.
|
|
165
|
-
6. Not verified: hot updates under a framework plugin (React Fast Refresh, Vue), server-side rendering, Vite library mode,
|
|
165
|
+
6. Not verified: hot updates under a framework plugin (React Fast Refresh, Vue), server-side rendering, Vite library mode, and Vite versions other than 8.3. An app with its own `package.json` in a workspace is covered by `nativele-monorepo`.
|
|
166
166
|
|
|
167
167
|
## Verify
|
|
168
168
|
|
|
@@ -173,16 +173,16 @@ npm run build # expect: ts-dom check: no issues, then ✓ built,
|
|
|
173
173
|
npx ts-dom doctor src/nv # expect: ts-dom doctor: the set-up looks right
|
|
174
174
|
```
|
|
175
175
|
|
|
176
|
-
Then run `npm run dev`, open every page and check that its components render and respond. Edit a template and check that the page reloads once and shows the change.
|
|
176
|
+
Then run `npm run dev`, open every page and check that its components render and respond. Edit a template and check that the page reloads once and shows the change. A reference implementation is the [`verify.mjs`](https://github.com/Pixmi/nativele/blob/main/skills/nativele-vite/example/verify.mjs) of the trial's example project, which checks with Playwright that `vite build` alone writes the generated files, that both built pages work under `vite preview`, and every row of the table in Known limitations, restoring the files it edits.
|
|
177
177
|
|
|
178
178
|
## Troubleshooting
|
|
179
179
|
|
|
180
180
|
| Symptom | Cause | Fix |
|
|
181
181
|
|---|---|---|
|
|
182
|
-
| `TS2307: Cannot find module './x.html.js'` from `npm run build` on a clean checkout | the build script starts with `tsc`, before anything generated the files | `"build": "ts-dom check <folder> && vite build"` |
|
|
182
|
+
| `TS2307: Cannot find module './x.html.js'` from `npm run build` on a clean checkout | the build script starts with `tsc`, before anything generated the files | `"build": "ts-dom check <folder> && vite build"`; for CI, `nativele-ci` |
|
|
183
183
|
| `vite build`: `[UNRESOLVED_IMPORT] Could not resolve './x.html.js'`; `vite dev`: `Failed to resolve import "./x.html.js"` and a 500 for the module | `dirs` is not relative to Vite's `root`, or leaves out the folder | give `dirs` relative to `root` (`["src/nv"]` with `root: "web"`) |
|
|
184
184
|
| `ts-dom check`: `[dir-not-found] The folder src does not exist` | the commands default to `src` in the folder they run in | pass the folder from there: `ts-dom check web/src/nv` |
|
|
185
|
-
| `ts-dom doctor`: `[tsconfig-misses-templates]`; `ts-dom check`: `TS18003: No inputs were found` | `include` is relative to the tsconfig, not to Vite's `root` | `"include": ["web/src"]` |
|
|
185
|
+
| `ts-dom doctor`: `[tsconfig-misses-templates]`; `ts-dom check`: `TS18003: No inputs were found` | `include` is relative to the tsconfig, not to Vite's `root` | `"include": ["web/src"]` (`nativele-typescript`) |
|
|
186
186
|
| An edit to a component has no effect until the page is reloaded by hand | a module calls `import.meta.hot.accept()` | remove it |
|
|
187
187
|
| A template edit never reaches the page, and the terminal shows `error [rule-id]` | the template breaks a template rule | fix it by the `Fix:` hint; once the template generates again, the page shows it |
|
|
188
188
|
| `vite dev`: `(!) Failed to run dependency scan ... failed to resolve rolldownOptions.input value: "web/index.html"` | `vite dev` resolves a relative `input` against `root` | write absolute paths, as in the example |
|
|
@@ -192,6 +192,10 @@ Then run `npm run dev`, open every page and check that its components render and
|
|
|
192
192
|
## See also
|
|
193
193
|
|
|
194
194
|
- The Vite plugin, its options and the dev server: https://github.com/Pixmi/nativele/blob/main/docs/tooling.md#with-vite-optional
|
|
195
|
-
-
|
|
195
|
+
- The `lint` block of `vite.config.ts` (Vite+) and the ts-dom rules: https://github.com/Pixmi/nativele/blob/main/skills/nativele-linting/SKILL.md
|
|
196
196
|
- What `ts-dom check`, `doctor` and `gen` check and write: https://github.com/Pixmi/nativele/blob/main/docs/tooling.md#checks
|
|
197
197
|
- Writing the components: `npx ts-dom skills nativele-core`
|
|
198
|
+
- The tsconfig: https://github.com/Pixmi/nativele/blob/main/skills/nativele-typescript/SKILL.md
|
|
199
|
+
- The whitespace mode with a formatter: https://github.com/Pixmi/nativele/blob/main/skills/nativele-formatting/SKILL.md
|
|
200
|
+
- CI: https://github.com/Pixmi/nativele/blob/main/skills/nativele-ci/SKILL.md
|
|
201
|
+
- An app in a workspace: https://github.com/Pixmi/nativele/blob/main/skills/nativele-monorepo/SKILL.md
|
|
@@ -3,8 +3,8 @@ name: nativele-vue
|
|
|
3
3
|
description: "Use Nativele web components inside a Vue 3 app: telling the template compiler which tags are custom elements, passing props, listening to events, replacing v-model, children and slots, lifecycle with v-for, v-if and KeepAlive, and SFC template types. Use when a project depends on vue and @nativele/ts-dom."
|
|
4
4
|
metadata:
|
|
5
5
|
tier: official
|
|
6
|
-
nativele: ">=0.
|
|
7
|
-
verified: "2026-11-
|
|
6
|
+
nativele: ">=0.6.0 <0.7.0"
|
|
7
|
+
verified: "2026-11-06"
|
|
8
8
|
tools: "vue@3.5.44 vite@8.3.6 @vitejs/plugin-vue@6.0.10 vue-tsc@3.3.14 typescript@6.0.3 @vue/tsconfig@0.9.1"
|
|
9
9
|
author: "Nativele maintainers"
|
|
10
10
|
detects: "vue"
|
|
@@ -25,7 +25,7 @@ Nativele components are native custom elements. Vue renders them like any other
|
|
|
25
25
|
|
|
26
26
|
| Tool | Verified version |
|
|
27
27
|
|---|---|
|
|
28
|
-
| @nativele/ts-dom | 0.
|
|
28
|
+
| @nativele/ts-dom | 0.6.0 (the last agent trial) |
|
|
29
29
|
| vue | 3.5.44 |
|
|
30
30
|
| vite | 8.3.6 |
|
|
31
31
|
| @vitejs/plugin-vue | 6.0.10 |
|
|
@@ -33,13 +33,13 @@ Nativele components are native custom elements. Vue renders them like any other
|
|
|
33
33
|
| typescript | 6.0.3 |
|
|
34
34
|
| @vue/tsconfig | 0.9.1 |
|
|
35
35
|
|
|
36
|
-
Verified on 2026-11-
|
|
36
|
+
Verified on 2026-11-06 in Google Chrome 148, starting from `create-vite` 9.3.4 with the `vue-ts` template, with the example project in the Nativele repository (`skills/nativele-vue/example`), and by an agent trial: a fresh agent did real work with only the Skill, and the result was checked independently. The example is a reference; it is not run in CI. With a different major version of Vue, treat every step as unverified.
|
|
37
37
|
|
|
38
38
|
## Set-up
|
|
39
39
|
|
|
40
40
|
1. Keep the Nativele components in their own folder, for example `src/nv/`, each as `x.html` plus `x.ts`, written with the core Skill (`npx ts-dom skills add nativele-core`). Give every Nativele tag one prefix that no Vue component uses, for example `nv-` (`define("nv-info-card", InfoCard)`); step 4 depends on it.
|
|
41
41
|
2. Install: `npm i @nativele/ts-dom`.
|
|
42
|
-
3.
|
|
42
|
+
3. The tsconfig that covers that folder must meet Nativele's requirements, `strict` among them (in the `vue-ts` template, `tsconfig.app.json` extends `@vue/tsconfig/tsconfig.dom.json`, which sets it). Check and adjust it with the TypeScript Skill (`npx ts-dom skills nativele-typescript`), which also says which TypeScript version `vue-tsc` needs.
|
|
43
43
|
4. Add the Nativele Vite plugin, and tell Vue's template compiler that the tags with the prefix are custom elements:
|
|
44
44
|
|
|
45
45
|
```ts
|
|
@@ -95,7 +95,7 @@ Verified on 2026-11-05 in Google Chrome 148, starting from `create-vite` 9.3.4 w
|
|
|
95
95
|
|
|
96
96
|
The component class must be exported and passed to `define()` in a folder that `ts-dom gen` scans, so it appears in `ts-dom-tags.ts`. A template ref is typed from the same map: `useTemplateRef<HTMLElementTagNameMap["nv-info-card"]>("card")`.
|
|
97
97
|
|
|
98
|
-
The generated files are not committed, so on a clean checkout the type check in `npm run build` runs before anything has written them and fails with `TS2307: Cannot find module './x.html.js'
|
|
98
|
+
The generated files are not committed, so on a clean checkout the type check in `npm run build` runs before anything has written them and fails with `TS2307: Cannot find module './x.html.js'` (why: `nativele-typescript`). Generate them first: `"build": "ts-dom gen src/nv && vue-tsc -b && vite build"` (the template's script with `ts-dom gen src/nv &&` in front). CI starts from such a checkout; the rest of what its job needs is in `npx ts-dom skills nativele-ci`.
|
|
99
99
|
|
|
100
100
|
## Example
|
|
101
101
|
|
|
@@ -252,13 +252,13 @@ Prove that the declaration types props: keep a `.vue` file that the app never im
|
|
|
252
252
|
|
|
253
253
|
`vue-tsc -b` passes only while each of these is an error; if the declaration stops working, it reports `TS2578: Unused '@ts-expect-error' directive`.
|
|
254
254
|
|
|
255
|
-
In the browser, against the dev server (production builds drop Vue warnings), check that an element with an object prop has no attribute for it (`el.getAttributeNames()`) and that `el.item` is the object, that the listener runs once per event, that a kebab-case Vue component still renders, and that there are no errors or `[Vue warn]` lines in the console.
|
|
255
|
+
In the browser, against the dev server (production builds drop Vue warnings), check that an element with an object prop has no attribute for it (`el.getAttributeNames()`) and that `el.item` is the object, that the listener runs once per event, that a kebab-case Vue component still renders, and that there are no errors or `[Vue warn]` lines in the console. A reference implementation of these checks is the [`verify.mjs`](https://github.com/Pixmi/nativele/blob/main/skills/nativele-vue/example/verify.mjs) of the trial's example project, which does them with Playwright, plus the `v-model` replacement, a component defined after mount, children that Vue reorders, adds and removes in both slot modes, and the lifecycle under `v-for`, `<KeepAlive>` and `v-if`. A Light DOM component has no `<slot>` elements once rendered; read a slot with `el.assignedNodes(name)`, where `""` is the default slot, and compare elements only, because Vue leaves comment and empty text nodes among the children.
|
|
256
256
|
|
|
257
257
|
## Troubleshooting
|
|
258
258
|
|
|
259
259
|
| Symptom | Cause | Fix |
|
|
260
260
|
|---|---|---|
|
|
261
|
-
| `TS2307: Cannot find module './x.html.js'` from `npm run build` on a clean checkout | `vue-tsc -b` runs before the generated files exist | start the script with `ts-dom gen src/nv
|
|
261
|
+
| `TS2307: Cannot find module './x.html.js'` from `npm run build` on a clean checkout | `vue-tsc -b` runs before the generated files exist | start the script with `ts-dom gen src/nv &&`; for CI, `nativele-ci` |
|
|
262
262
|
| `[Vue warn]: Failed to resolve component: nv-info-card` | `isCustomElement` is missing, or does not match the tag | set it as in step 4, with the prefix your tags use |
|
|
263
263
|
| A kebab-case Vue component (`<hello-box>`, `<router-view>`) renders as an empty element, with no warning | `isCustomElement` matches every hyphenated tag | match only the Nativele prefix (`tag.startsWith("nv-")`) |
|
|
264
264
|
| An object prop shows `[object Object]`, or the element has an attribute holding it | the element was not defined when Vue rendered it, or the prop is written in kebab-case | import the module before `mount()`; write `:selectedItem`, not `:selected-item`; for a module loaded later, use `.item` |
|
|
@@ -277,3 +277,5 @@ In the browser, against the dev server (production builds drop Vue warnings), ch
|
|
|
277
277
|
- Slots, Light DOM and Shadow DOM: https://github.com/Pixmi/nativele/blob/main/docs/components.md#light-default-and-shadow
|
|
278
278
|
- Moved elements, connecting and subscriptions: https://github.com/Pixmi/nativele/blob/main/docs/lists.md#moving-items-connecting-and-subscriptions
|
|
279
279
|
- Setup, the Vite plugin and checks: https://github.com/Pixmi/nativele/blob/main/docs/tooling.md
|
|
280
|
+
- The tsconfig and `vue-tsc`'s TypeScript version: https://github.com/Pixmi/nativele/blob/main/skills/nativele-typescript/SKILL.md
|
|
281
|
+
- CI: https://github.com/Pixmi/nativele/blob/main/skills/nativele-ci/SKILL.md
|
|
@@ -3,8 +3,8 @@ name: nativele-zod
|
|
|
3
3
|
description: "Validate a form inside a Nativele component with Zod 4 (or Valibot 1): read the values on submit and on blur, safeParse, map issue paths (also nested and array fields) to per-field messages in state shown with data-if, set aria-invalid and aria-describedby, focus the first invalid field, and emit the parsed data typed with z.infer. Use when a project depends on zod or valibot and @nativele/ts-dom."
|
|
4
4
|
metadata:
|
|
5
5
|
tier: experimental
|
|
6
|
-
nativele: ">=0.
|
|
7
|
-
verified: "2026-11-
|
|
6
|
+
nativele: ">=0.6.0 <0.7.0"
|
|
7
|
+
verified: "2026-11-06"
|
|
8
8
|
tools: "zod@4.6.7 valibot@1.5.0 vite@8.3.6 typescript@7.0.2 create-vite@9.3.4"
|
|
9
9
|
author: "Nativele maintainers"
|
|
10
10
|
detects: "zod valibot"
|
|
@@ -23,14 +23,14 @@ metadata:
|
|
|
23
23
|
|
|
24
24
|
| Tool | Verified version |
|
|
25
25
|
|---|---|
|
|
26
|
-
| @nativele/ts-dom | 0.
|
|
26
|
+
| @nativele/ts-dom | 0.6.0 (the last agent trial) |
|
|
27
27
|
| zod | 4.6.7 (the procedure was also run with 3.25.76, with the schema changes in limitation 10) |
|
|
28
28
|
| valibot | 1.5.0 (limitation 11) |
|
|
29
29
|
| vite | 8.3.6 |
|
|
30
30
|
| typescript | 7.0.2 |
|
|
31
31
|
| create-vite (`vanilla-ts` template, the starting point) | 9.3.4 |
|
|
32
32
|
|
|
33
|
-
Verified on 2026-11-
|
|
33
|
+
Verified on 2026-11-06 in Google Chrome 148, with Playwright against both the Vite dev server and `vite preview` of the production build, in a fresh `npm create vite@latest -- --template vanilla-ts` app set up with Nativele by the `nativele-vite` Skill (components in `src/nv/`). These steps use Zod 4.6.7; Zod 3.25.76 and Valibot 1.5.0 need only the schema changes in Known limitations 10 and 11. With any other major version of Zod or Valibot, treat every step as unverified.
|
|
34
34
|
|
|
35
35
|
## Set-up
|
|
36
36
|
|
|
@@ -257,7 +257,7 @@ What it does, as checked in the browser:
|
|
|
257
257
|
7. **Blur does not bubble.** Use `data-on-focusout` on the `<form>`, which receives every field's blur; `e.target` is the field. Validate the whole form and take only that field's message, so checks that read more than one field still apply. The example skips checkboxes on blur, because tabbing past an unchecked box would show its message too early.
|
|
258
258
|
8. **`aria-invalid` needs the value `"true"`.** `toggleAttribute("aria-invalid", on)` writes `aria-invalid=""`, which Chrome's accessibility tree reports as not invalid. Set `input.ariaInvalid = invalid ? "true" : null`. Whether a screen reader announces the message was not checked; the accessibility tree shows each invalid input with its message as the description.
|
|
259
259
|
9. **Checks across fields**: `.refine((d) => d.password === d.confirm, { message: "Passwords differ", path: ["confirm"] })` puts the message under `confirm`. Give such a refinement a `path`; without one its path is empty and the map key is `""`, which no field shows. In Zod 4 the object-level `refine` runs only when every failing field failed a check on a value of the right type (`too_small`, `invalid_format`, a field's own `refine`); a field that fails with `invalid_value` or `invalid_type` stops it, and the cross-field message is missing until that field is fixed. Those are `z.literal(...)` (an unchecked `z.literal(true)` box), `z.enum([...])` given an empty `<select>`, and `z.coerce.number()` given text. Write them so they fail with a check instead: a box as `z.boolean().refine((v) => v, "...")`, a select as `z.string().min(1, "Choose a role").pipe(z.enum([...]))`, a number as in the example (checked with `safeParse` in Node). Valibot's `v.forward(v.partialCheck(...))` does not have this problem.
|
|
260
|
-
10. **Zod 4 vs Zod 3.** These steps use Zod 4. The same component,
|
|
260
|
+
10. **Zod 4 vs Zod 3.** These steps use Zod 4. The same component, browser checks and `issue.path.join(".")` passed with Zod 3.25.76 after these schema changes:
|
|
261
261
|
|
|
262
262
|
| In the schema | Zod 4.6.7 | Zod 3.25.76 |
|
|
263
263
|
|---|---|---|
|
|
@@ -268,7 +268,7 @@ What it does, as checked in the browser:
|
|
|
268
268
|
|
|
269
269
|
`safeParse`, `result.error.issues`, `issue.path`, `issue.message` and `z.infer` were used the same way in both.
|
|
270
270
|
|
|
271
|
-
11. **Valibot 1.5.0 fits the same procedure.** Only `signup.ts` changes; the component, template and
|
|
271
|
+
11. **Valibot 1.5.0 fits the same procedure.** Only `signup.ts` changes; the component, template and browser checks passed unchanged:
|
|
272
272
|
|
|
273
273
|
```ts
|
|
274
274
|
// src/nv/signup.ts with Valibot
|