Repository navigation
Releases
v0.7.10
Summary
0.7.10 makes constructor-host-change read field initializers that a formatter wraps onto the next line, and keeps the README and llms.txt on ts-dom check.
Changes
constructor-host-changereads a field initializer wrapped onto the next line (readonly mark =thenthis.classList.add("x")) and one inside an object literal: a class member ends where its statement ends, not at every line break.- README (English and Traditional Chinese): the Quick Start and the short version use
ts-dom check, with thetsconfig.jsonit needs; the counter example, which repeated the first example, is removed. llms.txtsets up withts-dom check.ts-dom rules --explain=prop-forwardingno longer describes one application's plugin interface.
Breaking Changes
None.
v0.7.9
Summary
0.7.9 fixes lifecycle and Light DOM slot defects found in a real 0.7.3 to 0.7.8 migration, adds a lint rule for Custom Elements callbacks overridden without super, and widens two existing checks.
Changes
- Breaking: on every connection, the components inside a component run
connected()before it, in Light DOM and Shadow DOM. A component moved out and back in used to runconnected()before the ones inside it, the reverse of its first start, and a Shadow DOM component ran it before its shadow tree's components even the first time, so a parent that changed a child's elements inconnected()was undone by the child's ownconnected(). - A list or
data-ifof a parent template written directly inside a Light DOM component with slots puts its elements straight into their slot. Before, each update inserted them at the top level of the element and the slot moved them in afterwards: withoutmoveBeforethey were disconnected and connected again (losing focus, runningconnected()twice), also when the slot sat in a container the component keeps out of the document. - A component class's type declares
attributeChangedCallbackand the staticobservedAttributes, so a subclass can extend them withsuper. - New lint rule
callback-without-super(data-flow, warning):connectedCallback,disconnectedCallbackorattributeChangedCallbackoverridden withoutsuper, orobservedAttributesreplaced withoutsuper.observedAttributes, which silently stops the component from starting or from reading props from attributes. constructor-host-changealso reportsthis.insertBefore(...)and instance field initializers that change the element.dom-node-in-stateno longer reports a prop typed as a function that returns nodes.ts-dom doctorfollows a Vite or Vitest config's relative imports to a helper that returnstsDom()before reportingvite-plugin-missing.- Docs: a parent gives a child data through its props, also in its first render;
rules --explain=prop-forwardingsays where the rule does not fit.
Breaking Changes
- The order of
connected()on reconnection and in Shadow DOM components: the components inside now always run it first. Code that relied on a parent'sconnected()running before its children's on reconnection should set the children through their props instead.
v0.7.8
Summary
0.7.8 adds two lint rules that catch component code drifting from Nativele's design, and states the design principles in docs/design.md. Both rules are data-flow warnings whose Fix: links the principle they rest on.
Changes
- Lint rule
static-markup-in-code(data-flow, warning): a component class that creates an element withdocument.createElementand gives it a fixed text or attribute in the same block (b.textContent = "Remove",b.type = "button",setAttributewith a literal), structure the template can hold. A value that adds data, a write to another element, comments and strings are not reported, nor is an element whose content comes from data. - Lint rule
dom-node-in-state(data-flow, warning): astateorpropsvalue that holds several DOM nodes ([] as HTMLElement[],new Set<HTMLElement>(), aDocumentFragment), a copy of what the DOM holds. A single element such as an anchor a parent passes in is not reported. docs/design.mdstates the design principles in five parts: HTML describes, TypeScript decides; the browser is the runtime; data flows one way; small surface, checked by tools; integrations stay at the edge.npx ts-dom rules --explain=<id>explains both rules with an example.
Breaking Changes
None. New lint rules are warnings.
v0.7.7
Summary
0.7.7 fixes a browser-only failure in lists without data-prop: the custom elements in a new item were not upgraded when update ran, so calling a component's method there threw TypeError, and setting a prop created an own property that hid the component's setter.
Changes
- A list without
data-propimports each new item into the document (document.importNode), so its custom elements are upgraded beforeupdateand before the list sets their props. Since 0.7.6 callsupdatebefore inserting the item, a clone from the template's inert document was never upgraded in a browser; happy-dom upgrades such clones, so only a browser showed it. - A Chrome test covers a plain list whose
updatecalls a child'sbatch()and sets its props. - The testing Skill notes that happy-dom upgrades template clones and Chrome does not until they are imported.
Breaking Changes
None.
v0.7.6
Summary
Child components first render with the props their parent gives them, lists update a new item before inserting it, and Light DOM slots take only content written in HTML, so children a framework renders go to shadow: true components. Recorded in CHANGELOG under 0.7.6.
Changes
- Start order: a component inside another component, in its Light DOM or its shadow tree at any depth, starts after the outer component's first render, as a browser orders a shadow host and its shadow tree. A child of a template first renders with the props that render gives it. Starts are isolated from each other's errors, still run when the outer first render throws, and run once.
- Lists:
replace()andupsert()callupdatefor a new item before inserting it, as assigningitemsdoes; anupsert()whoseupdatethrows leaves no item behind. - Light DOM slots: they place the children an element has when it is built and nodes a list or
data-ifof a parent template puts in later. A node other code adds afterwards stays where it was put, with the console warningunplaced-childonce per tag. Slots move a node to another slot withmoveBeforewhere the browser has it. - Cleanups: every cleanup and
disconnected()runs when one throws; the errors are rethrown together. - Docs and Skills: the slot boundary is a design decision; the framework Skills give framework children
shadow: trueonly; render writes compare first; a prop the parent always gives is declared withnull, typedDeepReadonly<T> | nullin an interface. Seven Skills re-verified by agent trials on 0.7.6.
Verification
npm run check,npm test(764),npm run lint,npm run test:browser(124),npm run bench:check,npm run smoke,npm run smoke:no-bundler.- Chrome tests of the start order in both modes, of nested parsing, of
moveBeforein slots and of the slot rules; the start-order test fails without the change. - Fresh Sonnet agent trials of core, testing, react, vue, svelte, angular and integration, each checked again independently.
Breaking Changes
- Child components of a Light DOM template start after the parent's first render: in that render a child has not built its own content, so calling its methods there moves to a later render or an event handler.
replace()andupsert()runupdateon a new item before it is in the document: read layout after the list call.- Light DOM slots no longer place nodes that code or a framework adds after the element is built: give such a component
shadow: true, or put TypeScript content into an element the component exposes through a ref.
🤖 Generated with Claude Code
v0.7.4
Summary
Lint reads the components of the Nativele component packages a project depends on, findings from migrating a real application are fixed, diagnostics use one severity scale and one path per check, and the docs, Skills and tests are cut down and rewritten for reading. Recorded in CHANGELOG under 0.7.4.
Changes
- Component packages: lint,
ts-dom checkand the oxlint plugin check the components of each dependency that lists@nativele/ts-dom, read from the modules itsexportsname;ts-dom genstill writes only from the scanned folders. A tag declared only in TypeScript is listed as such byunchecked-custom-elements. - New checks:
constructor-host-change(a constructor that changes the element itself, which makes a browser create anHTMLUnknownElement),define-class-not-exportedints-dom check, and the runtime warningunslotted-nodewhen a Light DOM component removes a child with no matching slot. Lint followsextendsto theComponent(...)class a subclass extends. - doctor: only errors and warnings (
skill-outdatedis a warning;ts-dom skillsshows which Skills cover the project's dependencies), nostale-generatedand no--include/--exclude/--whitespace,--ignoreadded. - One path per check:
duplicate-definewithin and across folders, onestale-generatedmessage, one issue formatter, each id once ints-dom rules,--ignorereachingunchecked-content. - Fixes: comments among a Light DOM host's children stay where they are; lifecycle callbacks are declared on the component type (no TS4113); several
tsDom()share one watcher listener (noMaxListenersExceededWarning); the runtimedata-properror isitem-prop-missing. - Docs and Skills: duplicated, stale and wrong passages removed; every passage restructured under writing rules now in
docs/contributing.md; all 19 Skills re-verified by agent trials on 2026-11-08. - Tests: shared helpers, duplicate tests removed, browser tests on ephemeral ports, a real-browser test of the constructor behavior and the slot warning.
- Versioning policy: any 0.x version, a patch included, may contain breaking changes, marked in its section.
Verification
npm run check,npm test(751),npm run lint,npm run test:browser(118),npm run bench:check.- Fresh Sonnet agent trials of all 19 Skills from packed builds, each checked again independently; the four Skills changed afterwards (core, linting, testing, formatting) trialled again.
Breaking Changes
ts-dom doctorno longer takes--include,--excludeand--whitespace, no longer reportsstale-generated(usets-dom gen --checkorts-dom check --no-write), and its--jsonhas noinfoissues;skill-availableis gone.
🤖 Generated with Claude Code
v0.7.3
Summary
Nativele 0.7.3: fixes found by migrating a real application to Nativele: list items at the top level of a Light DOM template are no longer removed, Light DOM slots place nodes from where they are, another template system's ./x.html imports are left alone, and several diagnostics point at the right fix.
Changes
- Light DOM slots: a
<template data-each>at a Light DOM template's top level keeps the items it inserts after the first render (adds, removes, reorders, inserts while disconnected); it used to lose them a microtask later, or have them moved into the default slot. Slot content is placed from the nodes' current positions, so a node moved within the same task, a node added while disconnected and a slot's fallback (with itsdata-ifblocks and lists in their last state) all end up where they belong. - Template imports: lint,
ts-dom checkand the oxlint plugin treat only./x.html.jsas a Nativele template import;./x.html(another template system's import) is no longer linted as one, andts-dom doctorstill reports a Nativele import without.js. docs/tooling.md describes how two template systems coexist. - unused-ref: refs destructured from any
.refsexpression, renamed, quoted, nested or followed byas/satisfiesor no semicolon count as used;refs: { … }in a type or object literal no longer hides an unused ref. - Fix hints: the a11y name rules say to give an element a
data-refwhen TypeScript sets its name;TS2307for a missing./x.html.jssays to runts-dom genand scan the template's folder. - Robustness: a folder that vanishes during a run, or a symbolic link to nothing, is skipped instead of crashing a long-running host; the bin path is written as npm normalizes it.
- Skills:
nativele-linting(coexisting template systems,data-refand the a11y name rules),nativele-monorepoandnativele-vite(onetsDom()per workspace package, its dev server watches those folders),nativele-core(points at the store adapter),nativele-state-management(getSnapshotclients); each re-verified by a fresh agent trial on 2026-11-08.
Breaking Changes
None. A module importing a template as ./x.html (without .js) is no longer linted as a Nativele template; ts-dom doctor reports it (template-import-without-js).
v0.7.2
Summary
Nativele 0.7.2: library elements are checked against their custom elements manifests, misspelled events on native elements are reported, component trees of any depth type check, and Skill trials and performance budgets are scripted.
Changes
- Custom elements manifests: lint reads the
customElementsmanifest of the template's package and its dependencies (no node_modules scan), sounknown-prop,invalid-prop-value(literal unions with Did you mean,="false"on a boolean attribute, NaN numbers),unknown-event, and the newunknown-slotandunknown-custom-elementcheck library elements such as Web Awesome's; completeness is judged per element along its superclass chain; manifest-known tags leaveunchecked-custom-elements; doctor reports a broken manifest (custom-elements-manifest). unknown-native-event(new): adata-on-*name on a native element that is close to one of its native events, and that no component, dispatched event or manifest declares, with Did you mean; not reported when the element holds content whose events lint cannot know.- Types: component trees of any depth, recursive and mutually recursive components type check (no TS2589, no circularity).
- Fixes: data-flow issues in
--jsoncarry only the documented keys;emit-forwardingandcustom-event-on-nativepoint at the reported attribute;unguarded-input-valuetreatsvalue,valueAsNumberandvalueAsDateas one and counts only a comparison that gates the write; the Vite plugin parses each template once; the release workflow builds before staging so npm sees the bin file. - Skills and tooling: scripted Skill trials (
npm run trial, fixtures intrials/, replay of the last accepted agent output in CI, first accepted trial fornativele-vue); performance budgets in CI (npm run bench:check: parse/read/readdir counts, memo entries, tsc instantiations, a scaling ratio);nativele-vue,nativele-integration,nativele-web-awesomeandnativele-lintingupdated from trials (object props change by a new object,<KeepAlive>caches components, manifest checks). - Node:
engines.nodeis>=22(CI tests 22 and 24).
Breaking Changes
None in the public API. --json issues of the data-flow rules no longer carry undocumented extra fields (tag, attrs, values, events, slotted).
v0.7.1
Summary
Nativele 0.7.1 makes any unable to switch the HTML–TypeScript checks off, and makes lint and codegen faster.
Changes
any-in-contract(new check):anyin a component'sstate,props,derive,emitsdetails, its template (Template<any>or an untypedTemplate), a handler member or a handler's first parameter is a tsc contract error, whichts-dom checkreports at the declaring key, theComponent(...)call or thedata-on-*attribute, with a Fix. Only the data the component declares is looked into (objects, arrays, tuples, index signatures, Map, Set); DOM and other library types stop the search, sonull as HTMLElement | nullor aCustomEventin state is not reported.unknownnever triggers it.anyfrom outside types: ananyin lib.dom, a third-party element class,HTMLElementTagNameMapor a child's contract is treated as not declared everywhere the types look things up, instead of satisfying a check by accident or turning an event intounknown.- Library source:
typescript/no-explicit-anyis an error in the repository's own lint. - Performance: each scanned folder is read once per run; the declared props and emits of each component are kept between runs; each folder's package is found once per run (1000 components: single-file oxlint re-lint about 21 to 13 ms, Vite template save about 45 to 29 ms,
lint --a11yabout 330 to 295 ms); a DOM-typed state field no longer expands lib.dom in tsc. - Skills:
nativele-lintingexplains whereanyis reported and in which order; re-verified by an agent trial.
Breaking Changes
- Code with
anyin a component contract now failstsc(anyInContract: "props.item"and the like): declare a specific type, orunknownand narrow it where it is read. Component(template([...]))without type arguments (an untypedTemplate) is nowanyInContract: "template": import the template from its./x.html.jsmodule.
v0.7.0
Summary
Nativele 0.7.0 checks more of the contract between HTML and TypeScript: a data-on-* handler's parameter is checked against the event it is bound to, a form's elements and a list item's el are typed from the template. Lint, ts-dom check, codegen and the oxlint plugin now read how templates, classes and define() calls relate from one index that follows imports, barrels and namespaces, so they agree with each other on any file layout and stay current in the editor and the Vite dev server. The accessibility rules judge an element by its composed content, including what child components render into it, and say so with unchecked-content when they cannot. This release has breaking changes; see below.
Changes
Types and checks
- A
data-on-*handler may declare its event as its first parameter (onPick(e: EmitEvent<Picker, "pick">),onKey(e: KeyboardEvent));define()checks it against the event the element declares for that name (the child'semits, the element'son<event>property, thenHTMLElementEventMap), andts-dom checkreports a mismatch ashandler-event-typeat the attribute.this.on()checks an annotated parameter the same way. - A
data-refon a<form>typeselementswith the controls inside it bynameandid; a misspelled name is a tsc error. - A list item's
elis typed by the item's root tag: the item component's class for a component list, the element type for plain items. - New errors and warnings:
each-in-svg(data-eachinside<svg>or<math>),unchecked-custom-elements(custom elements lint has no single definition of, listed once per run with the cause and fix of each), and the a11y warningunchecked-content. ts-dom lintandts-dom checktake--ignore=<rule-id>(repeatable) to leave out warnings.
Lint and tooling
- One component index follows templates and classes through re-exports, barrels and namespaces and finds a class whose
define()is in another file, so such components are ints-dom-tags.ts, have typedrefs, and get their props, events and template checked. ts-dom checkpointsmissing-binding,missing-handlerandhandler-event-typeat the template of the class the error is about, for every missing name, and keeps independent errors inside a broken class.role-tabindexandclick-semanticsno longer overlap;click-semantics,control-nameandheading-emptyread what child components render, slots filled, so<div data-on-click><button>and a button whose name comes from a child component pass.custom-event-on-nativeuses lib.dom's event names and reports only an event a component emits withoutbubbles: true.- The oxlint language server and the Vite plugin follow file changes across files (a child template, a new
define(), apackage.json) instead of keeping what they read first; the Vite plugin'sa11ygives the same results asts-dom lint --a11y. - Faster on large projects: each template is parsed once per run, a
define()save regenerates only the templates that use the changed tags, andts-dom gen --watchparses only the saved template.
Fixes
- A
data-on-*inside adata-ifblock of a list item now fires. ts-dom lintandts-dom genreport a missing folder asdir-not-foundinstead of crashing.- Templates imported from any folder, imported without
.js, or used by a generic component class are found and checked.
Documentation and Skills
- New Official Skill
nativele-web-awesome;nativele-svelte,nativele-angular,nativele-zod,nativele-tanstack-queryandnativele-tailwindare Official. - Every library rule is stated once in
docs/and linked fromllms.txt; new recipes for request cancellation, config-driven tables, form-associated components and switching the language;AGENTS.mdis a guide for agents that use the library.
Breaking Changes
Schema["events"]maps each handler to the[tag, event]pairs it is bound to instead of being a union of handler names. Migration: only a schema written by hand fortemplate<...>()changes; useevents: Record<never, never>for a template without handlers.- A handler whose first parameter does not accept the bound event (
KeyboardEventon aclick,InputEventon achange) is a tsc error (wrongHandlerParameters). Migration: declare the event type the error names, or type the parameterEventand narrow it in the body. - A list item's
elis no longerElement, so a cast such asctx.el as HTMLInputElementon an<li>item fails. Migration: remove the cast, or cast to the element the template has at the root. - The lint rule
missing-handleris removed fromts-dom lintand the oxlint plugin (ts-dom/missing-handler); tsc reports a missing handler atdefine(), andts-dom checkreports it at the template under the same id. Migration: dropts-dom/missing-handlerfrom the linter config, and runts-dom checkortscwhere onlyts-dom lintran. emitsnamedfocusin,focusout,compositionstart,compositionupdate,compositionend,touchstart,touchmove,touchendortouchcancelthrows[native-event-name]in every browser (tsc already reported it). Migration: rename the event, for example with a prefix.- A custom event emitted with
bubbles: trueis handled in the bubble phase, so astopPropagation()between its target and the handler now stops it. Migration: where the handler must still receive it, do not stop its propagation below that handler.