Repository navigation
Nanoviews 1.0 🎉
Nanoviews' first stable release is out, together with Nano Kit 2.0, whose signals it shares. A view is a tree of element calls, attributes first and children second, that builds real DOM once. The signals bound into it update their own nodes in place: no JSX, no virtual DOM, no re-render, in 3.5 to 7 kB minified and brotlied.
import { signal, length } from 'nanoviews/store'
import { form, input, ul, li, p, mount, component$, for_ } from 'nanoviews'
const Todos = component$(() => {
const $todos = signal(['Release 1.0'])
const $draft = signal('')
return (
form({
onSubmit(event) {
event.preventDefault()
$todos(todos => [...todos, $draft()])
$draft('')
}
})(
input({
placeholder: 'What next?',
value: $draft
}),
ul()(
for_($todos)(
$todo => li()(
$todo
)
)
),
p()(
'Total: ', length($todos)
)
)
)
})
mount(Todos, document.querySelector('#app')!)
// <form><input placeholder="What next?"><ul><li>Release 1.0</li></ul><p>Total: 1</p></form>Start with the documentation.
⚠ BREAKING CHANGES
-
nanoviews:
classListreturns a plain string when there is no accessor among the parts.
Its result type says which of the two comes back. -
nanoviews:
createEffectAttribute,value$,checked$,selected$,files$,ref$,
style$andautoFocus$are gone, along with theEffectAttributeValuesand
EffectAttributeTargetsaugmentations.styletakes an object,textareatakes no
children, and a plainvalueorcheckedsets the DOM property. Files are read from the
onChangeevent.- feat(nanoviews): bind muted on media elements and settle the control bindings
audioandvideoare factories of their own:mutedis bound through the DOM property,
two-way with a writable signal. The controls after a review: a signal of a number is novalue,
the shape of a select'svaluefollowsmultiple, a value is always written outside the focus
so a default set later cannot replace it,defaultCheckedleaves the indeterminate state alone,
the selection keeps its direction,checkedtakes theIndeterminatesymbol only, and a
select also follows the text of its options. The key order is documented where it matters. -
nanoviews:
props$and theProps$type are no longer exported fromnanoviews.
Destructure the props in the render and pass them on as they came, reading a value with$get
where an expression needs it. -
storybook,testing-library:
renderof@nanoviews/testing-libraryno longer takes a[component, ...args] -
nanoviews: a boolean child, or an accessor that returns a boolean, renders nothing
instead of the texttrueorfalse. Turn the value into a string to show it. -
nanoviews: children passed to a component or a slot whose render has no
children
parameter are a type error. -
nanoviews: element and block calls return descriptions instead
of nodes,div()('x')describes the element anddiv()('x')()builds
it, and a view is built only undermount, since bindings and
effect$need its scope.children$is removed in favour of
component$;contextandisolatearecontext$andisolate$
and take one child;effectandeffectScopeare no longer exported
fromnanoviews, useeffect$in components andeffectfrom
nanoviews/storein stores. kida 2.0.0-prerelease.20260913103613 is
required. -
nanoviews: import
provide,inject,getContextandrunfromnanoviews/store
instead ofnanoviews. -
nanoviews: the
classList$effect attribute is removed.
Pass the parts toclassinstead:class: ['button', () => $primary() && 'primary']. -
the packages require Node.js 24 or newer.
Features
- agera,intl,kida,nanoviews,query,router,svelte-kit: rename
ValueOrAccessortoSignalish(#210) (c42723a) - agera,kida,nanoviews: bottom-up deferred effect scopes (#189) (dd3169f)
- agera,nanoviews: add
show_with pausable effect scopes (#225) (4c2490d) - agera: add
selectorto wake only the keys whose answer changed (#200) (ac6b35f) - agera: derive mounted state from the graph instead of counting subscribers (#191) (9c43fce)
- agera: keep the source cold when observing through a derivation (#199) (ecc0434)
- intl: pass unique index to rich tag handlers to use as framework key (#187) (5b4008b)
- intl: support self-closing tags in rich-text formatter (#185) (fa4fcb8)
- kida,store: move tasks from
@nano_kit/storetokida(#220) (2e5c07c) - nanoviews: accept an
InjectionContextinstance incontext$(#42) (c3a07d8) - nanoviews: accept read-only accessors in
value$,checked$andselected$(#32) (e902e6a) - nanoviews: add
as_to hand a row through a transform (#207) (2891ec4) - nanoviews: add
match_for a cascade of conditions (#219) (1065b20) - nanoviews: add
polymorphic$for components that render the target given inas(#76) (3a72092) - nanoviews: add
props$to read any prop in accessor form (#212) (3cd1d77) - nanoviews: add
show_switch_andshow_match_that keep every case alive (#51) (2898695) - nanoviews: add the
nanoviews/svgentry point (#21) (a0ecfe9) - nanoviews: bind ref, style, autoFocus and the form controls through attributes (#40) (98c2690)
- nanoviews: expose
swap_, the blockif_andswitch_are built on (#203) (9fc639f) - nanoviews: hand the tracking key to the row (#217) (34948cd)
- nanoviews: infer from the render whether a component takes children (#44) (6553633)
- nanoviews: lazy descriptions,
component$and slots (#22) (68bbe84) - nanoviews: let an effect attribute name the element it sits on (#206) (215f157)
- nanoviews: remove
props$from the main entry (#52) (d7929da), closes #30 - nanoviews: remove
provide,inject,getContextandrunfrom the main entry (#45) (47cca5a) - nanoviews: rename
$$children,$$slotand$$slotsto a trailing$(#209) (47f794b), references #188 - nanoviews: rename effect attributes from
$$nametoname$(#188) (468a293) - nanoviews: rename the truthy and falsy narrowing types (#211) (577c49d)
- nanoviews: render nothing for
trueandfalsechildren (#43) (fc3b714) - nanoviews: support
classList$on SVG elements (#35) (6db45a3), closes #29 - nanoviews: take class lists in the
classattribute (#38) (36fc036) - nanoviews: type modern HTML attributes and events (#34) (7df71c2)
- require Node.js 24 (#47) (617cdd7)
- router: add the nanoviews integration of
@nano_kit/router(#53) (87fb7f6) - ssr: add server entrypoint (#164) (eefd560)
- storybook,storybook-vite,testing-library: publish the packages and rework the story API (#5) (6d72f43)
- storybook,testing-library: return a composed story unbuilt, like a component instance (#77) (786d0b9)
Bug Fixes
- agera,kida,nanoviews,query: run user reducers and event handlers untracked (#193) (03c78db)
- deps: update dependency magic-string to v1 (#175) (fbf537c)
- deps: update dependency starlight-llms-txt to ^0.11.0 (#85) (4ff267b)
- deps: update nano_kit packages to 2.0.0 (#81) (0e2da00)
- deps: update nano_kit packages to 2.0.0-prerelease.20260919114914 (71ed3a4)
- deps: update nano_kit packages to 2.0.0-prerelease.20260927130800 (#50) (ed214f9)
- deps: update nano_kit packages to 2.0.0-prerelease.20261008124401 (#71) (1378608)
- deps: update nano_kit packages to 2.0.0-prerelease.20261014204046 (#73) (3eb3bc3)
- kida: keep a
resolvedfactory unstarted until the first read (#221) (bc13a53) - kida: keep a child write in the caller's context (#198) (0816533)
- kida: type
toAccessorby what it actually returns (#208) (024e812) - nanoviews: apply multi-word and custom style properties (#195) (3270183)
- nanoviews: drop the React-only attribute keys (#19) (58b8ffd)
- nanoviews: fire every
on*prop, not just the bubbling ones (#204) (42e613b) - nanoviews: keep the
uninspectedmark on the rows of a read-onlyfor_(#46) (f02d052) - nanoviews: let
falseremove a boolean attribute (#18) (7739fcb) - nanoviews: let a slot reach
children$and fail loudly when undeclared (#10) (eea8827) - nanoviews: show the
for_placeholder when there is no array at all (#205) (6e6568b) - nanoviews: type
styleobjects without installingcsstypeseparately (#63) (89c7879) - nanoviews: type
throw_asnever(#11) (79a85da) - nanoviews: type the value of a
when_child insidematch_(#65) (a10b537) - nanoviews: unmount a fragment whose children render nothing (#64) (26b05fd)
- router: preserve
statusCodeof loadablenotFoundpages (#166) (40da5a6) - storybook: apply the annotations of
setProjectAnnotationsto composed stories (#66) (8d91e4c) - storybook: derive plain args from the
Signalishprops of a component (#36) (307ece7), closes #28 - storybook: render a story inside the
context$of its decorator (#72) (53b8f48)
Performance Improvements
- agera,kida,store: replace
morphwith the signal constructor protocol (#197) (23b3370) - agera,nanoviews: cut allocations and graph work on the binding paths (#196) (3d1c93b)
- agera: speed up effect runs by splitting warmup and rerun paths (#178) (f550458)
- benchmark-nanoviews: take the row key and drop
record(#218) (66e9ee3) - nanoviews: clear a row range with
replaceChildren(#216) (5942baf) - nanoviews: create the effect attribute registry on first use (#213) (4113217)
- nanoviews: inline the property and event names in the control effect attributes (#33) (ca9d009)
- nanoviews: join a class list with no accessors once, without an effect (#41) (d1038cf)
- nanoviews: wake only the rows whose value changed (#202) (c71cc9c)