Skip to content

Installation

Install the package using your favorite package manager:

pnpm add nanoviews

Nanoviews needs no compiler, JSX transform or bundler plugin: a view is plain TypeScript. A new project can start from the vanilla-ts template of Vite:

  1. Create the project

    pnpm create vite my-app --template vanilla-ts

    When it asks whether to install and start now, answer no: the next steps do both.

  2. Install Nanoviews

    Go into the my-app folder and install nanoviews there with the command above.

  3. Write the app

    The template’s index.html already holds the container the app mounts into, and loads src/main.ts as a module script:

    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>

    Replace the content of src/main.ts with the Quick Start below. The rest of src/ is the template’s own demo and can go.

  4. Start the dev server

    pnpm dev

    Then open the URL it prints.

The template needs no Vite config, and its tsconfig.json stays as it is. The Vite Demo is a complete project of this kind.

With no compiler to run, Nanoviews works without a bundler too, straight in the browser. A CDN that serves npm packages as ES modules, such as esm.sh, loads it, and an import map keeps the imports the same as in a project, nanoviews/ covering nanoviews/store and nanoviews/svg. The code is plain JavaScript then:

<div id="app"></div>
<script type="importmap">
{
"imports": {
"nanoviews": "https://esm.sh/nanoviews",
"nanoviews/": "https://esm.sh/nanoviews/"
}
}
</script>
<script type="module">
import { signal } from 'nanoviews/store'
import { button, component$, mount } from 'nanoviews'
const Counter = component$(() => {
const $count = signal(0)
return (
button({
onClick() {
$count(count => count + 1)
}
})(
'count is ', $count
)
)
})
mount(Counter, document.querySelector('#app'))
</script>

Here is a minimal app: a counter component, mounted into the page.

import { signal } from 'nanoviews/store'
import { main, h1, button, component$, mount } from 'nanoviews'
const Counter = component$(() => {
const $count = signal(0)
return (
button({
onClick() {
$count(count => count + 1)
}
})(
'count is ', $count
)
)
})
const App = component$(() => (
main()(
h1()('Hello, Nanoviews!'),
Counter()
)
))
mount(App, document.querySelector('#app')!)
// <main><h1>Hello, Nanoviews!</h1><button>count is 0</button></main>
Entry pointExports
nanoviewsHTML element factories, components (component$, slot$, slots$), effect$, context$ and isolate$, blocks (if_, show_, switch_, match_, for_…), mount, helpers (fragment, classList, portal, shadow, dangerouslySetInnerHtml) and their types.
nanoviews/storeSignals, computeds, effects, operators, records, async data and dependency injection.
nanoviews/svgSVG element factories (svg, path, circle…) and their types.

nanoviews/store re-exports the reactive core of Nano Kit, the one @nano_kit/store extends, so the signals of Nano Kit packages bind in views as they are, as long as a single copy of the core is installed: see Nanoviews and Nano Kit.