Practical examples. Live demos.
Pick an example to open it full screen, with the live preview and its source side by side.
Basics
4The patterns every Nuclo app is made of.
Counter
Mutate state, then call update(). The dynamic text refreshes.
Todo List
Use list() for repeated items. Call update() after each mutation.
Search Filter
Filter an array with plain JavaScript. Render the result with list().
Styling
Use css() for classes. Use cx() for small conditional changes.
Components
4Plain functions with static and dynamic params, children, lists matched by identity and nested data. Every preview counts its mounts.
Static & Dynamic Params
A value param is read once, when the component is built. A function param is read on every update(). The component itself runs once either way, and the mount count proves it.
Children & Modifiers
A component forwards its children with a spread: builders, text, attribute objects and modifiers. Conditional parts go in when(), so the component around them is never rebuilt.
List Identity
list() keeps a row while its item is in the array: reorder, insert and rename without losing inputs or focus. A switch clones the objects on every update to show what breaking identity costs.
Nested Data
A team with members with tasks: one component per level, nested list() calls, derived counts as functions over the same objects. Deep changes patch only their own nodes.
API
13One small demo per building block, the same ones the docs embed.
Tag Builders
A builder takes attributes, static children and dynamic text. Rename changes the state, then calls update().
Components
A component is a plain function. Each Counter() call keeps its own count.
Attributes
Attribute values can be functions. The second button flips busy and calls update(); Save's disabled and aria-busy follow.
Events
onInput and onKeyDown are plain attributes. Type, then press Escape to clear.
Lifecycle
onMount starts an interval and returns its cleanup. Unmount runs the cleanup, so the count pauses until the timer mounts again.
Explicit Updates
count++ only changes the variable. The text catches up on the next update(), from the button or anything else on this page.
Dynamic Values
Edit the name. The static text was fixed when the element was built; the dynamic one runs again on every update(). forceUpdate() rebuilds the tree, so the static text catches up too.
update()
Every update() runs every dynamic value, even when its data did not change. Other demos on this page push the count up too.
scope()
Both buttons add an item and rename the user. update('cart') refreshes only the scoped panel.
when()
The first true condition wins; otherwise .else() renders. A new branch is built from scratch.
list()
Rows are matched by identity. Check a row, then Reverse: the same <li> moves, checkbox and all.
region() & into()
A layout with a stacked main region and a side region, filled from outside it. Type into Home, open the dialog and close it: the text stays. Article fills both regions with one into().
forceUpdate()
update() refreshes only the dynamic lang line. forceUpdate() calls App again and patches the same <h1>. The explicit form rebuilds only this tree, not the whole page.
Styling
3Create a class, compose a class, and use a tiny theme.
Forms
3Validation as plain functions over plain state, touched fields, steps and dynamic rows.
Field Validation
Rules as a function over plain state, errors shown once a field was touched, a debounced async check with a pending state, and a submit that waits for all of it.
Multi-step Wizard
Three steps as when() branches over one data object. Next touches the step's fields and advances only when they pass. Review lists everything with Edit links.
Dynamic Rows
Invoice lines in an array rendered with list(). Each row validates itself, the total counts the valid ones, and rows keep their inputs when others are added or removed.
SVG
27Charts, animations, tools and games from the SVG tag builders, driven by plain data, pointer events and update().
Bar Chart
Rects from an array. Their y and height are functions of the data, so update() moves the bars.
Line Chart
A path whose d is built from the points, with a gradient area and one circle per point.
Donut Chart
One circle per slice. stroke-dasharray gives each its share of the ring and stroke-dashoffset its start.
SVG Animation
SMIL as builders: animateSvg pulses the sun, animateTransformSvg orbits the planet. A dynamic dur sets the speed.
Gauge
An arc that fills with stroke-dashoffset and a needle that turns with a CSS transform. Both are functions of one number.
Radar Chart
Five values on five axes. The shape is one path whose d is computed from the data, so update() morphs it.
Heatmap
A grid of rects whose fill-opacity follows a level. Click a cell to bump it; a titleSvg child is its tooltip.
Hover Tooltip
Pointer events on SVG elements. onPointerEnter picks the active point and a tooltip group slides to it.
Curve Editor
Drag the handles of a cubic Bรฉzier. onPointerDown picks a point, onPointerMove on the svg moves it and the path follows.
Clock
Hands are lines whose transform is a function of the time. onMount starts the ticking and returns the cleanup.
Icon Toggles
A menu icon that morphs into a cross with CSS transitions, and a heart that pops with a SMIL animation that begins on click.
Live Stream
Two series scroll left on a timer. A CSS transition as long as one tick makes the slide smooth, and hovering reads any sample.
Candlestick Chart
Forty slots read their own candle. Change the timeframe, toggle the average, hover for the numbers, or let the live candle tick.
Bar Chart Race
Ten bars never leave the DOM. Their rank sets a translateY, so a transition slides each one to its row as the values change.
Stacked Area Chart
Four bands morph between stacked, stream and percent layouts. Hiding a series only gives its band zero thickness, so every path keeps its shape.
Treemap
A squarified layout you drill into. Switching the metric slides every cell to its new box, and clicking a group swaps in its children.
Live Histogram
Samples pour in from four distributions. The bins re-count on every change, a fitted bell follows the mean, and a slider sets the bin count.
Drawing Pad
Pointer events draw polylines. list() renders one per stroke, and the stroke in progress grows on every update().
Rotary Knob
A custom slider: the pointer's angle sets the value, the arrow keys step it, and pathLength="100" turns the value into a dash.
Color Wheel
Pick a hue by angle and a saturation by distance. Ninety wedges, a radial gradient and a dark disc make the wheel.
Spirograph
A wheel rolls inside a ring and a pen traces it. Each frame lengthens one dash and updates only its scope().
Bouncing Balls
Gravity, walls and collisions in a requestAnimationFrame loop. Pull back and let go to launch a ball.
Gooey Blobs
A blur and a color matrix filter melt blobs together. A trail of circles follows the pointer.
Force Graph
Nodes repel, links pull, and the layout cools until it rests. Drag a node, or click one to grow a child.
Brush & Zoom
Brush a range on the overview to zoom the chart above. A clipPath that follows the brush colors the selection.
Tic-Tac-Toe
Play the computer. when() adds each mark, and a CSS animation on its dash draws it in.
Circular Text
Type a badge. textPath bends the text around a circle and textLength fits it to exactly one lap.
Routing
6Route tables, matching, the active route, layers and loaders. nuclo-router is a separate package: npm install nuclo nuclo-router.
A Routed App
A real app with its own router, running in the frame: a route table, one outlet(), plain links, a pending state and a 404. Click around, then use Back.
Nested Routes
Docs is a layout with child routes. A topic renders in its outlet() and ./topic links resolve against the layout's route. Type in the notes, then switch topics: the layout is never rebuilt.
Route Loaders
The post page exports a load() that runs before the page is built. Watch router.pending while it waits, and the error state with Retry when it throws on the broken post.
Layers
The order form pushes the customer page as a layer and awaits its result. The form is not re-rendered, so its notes survive. Save resolves the push, Cancel or Back dismisses it.
Multiple Routers & Loading
Two routers, two spinners. The shop layout and its section both have load()s: they run in parallel under one router.pending. The sidebar has a router of its own, created but never started, with its own loading flag refreshed from onNavigate.
Pattern Matching
Static, :param and *rest patterns, and a section table mounted under two parents. Type a path and watch match(), which resolves without loading anything.
Apps
15Bigger programs, full screen, with their real source behind tabs: a desktop with windows, a data grid, a chat, games, editors and libraries that own their own state.
Page Builder
Write directly on the page, drag grips to reorder blocks or move them into layouts, press / to insert, and right-click for actions. Style grid and flex layouts, undo edits, preview at phone size and export HTML.
Algorithm Stepper
The engine is plain JavaScript: generators that mutate an array and yield after every step. The player calls next() and update(); the bars are a list() over the same objects, so a swap moves two elements.
Kanban Board
A team board: add tasks, assign them to people, edit them in a dialog, filter by person or search, drag them between columns and undo a delete. Columns and cards are plain arrays of the same objects; every move is a splice(). Rows are matched by identity, so dragging, sorting, assigning or editing a card reuses its element. The mount count on screen proves it.
three.js Inspector
A library that owns its own state. The panel reads positions, colors and flags straight from the three.js objects and writes edits back to them. The render loop calls update() once per frame; nothing is mirrored.
Infinite Scroll
A feed with no end: a fast fake fetch() generates every page on the fly into one plain array. Only the rows near the viewport are in the DOM: the list() renders posts.slice(start, end) between two spacers, so the page stays light at a hundred thousand posts. A sentinel at the real end asks for the next page before it comes into view.
Desktop
A working desktop with Files, Notes, Terminal, Calculator, Timer, a Kanban board, Finance and a Calendar. Create and organize folders, edit notes, and use shell commands on one shared simulated disk saved in your browser. Type into the Calculator straight from the keyboard, click anywhere in the Terminal to focus its input line, drag cards between columns on the board, or keep a ledger in the Finance spreadsheet and watch its charts move โ the ledger lives in IndexedDB. Windows keep their state as you move, resize and switch between apps; a running timer fills the taskbar tray with into().
Node Graph
Wire numbers, text and switches through math, comparisons and If nodes, and every value updates as you type. Functions are graphs too: their Input and Output nodes are the ports of every Call, and a Call can name its own function, so factorial and sum recurse with an If as the way out. The engine is plain JavaScript: each node is a generator that yields to ask for an input, and one loop drives them from its own stack, so sum(50000) nests fifty thousand calls deep in about a tenth of a second without touching the JavaScript call stack. Only a step budget stops a recursion with no way out. Dragging writes x and y and updates only the canvas scope; the run count shows the graph never runs for a move.
Data Grid
A work table over 10,000 plain row objects. Search, filter, sort and paging are plain functions over the array, and the table body is a list() over the current page. Rows are matched by identity, so sorting moves the rows that stay on the page, and an edited row is the same object everywhere. The rows-built count proves it.
Chat
A chat with three channels, each one plain object: its history, cursor, typing, draft and scroll position, so switching keeps every channel exactly as it was, and update("chat-sidebar") refreshes only the unread badges. History loads upward forever with unshift() and a scrollTop that grows by the height it added. Your message shows before the server has it, send() patches the same object, and Retry, Edit, Delete and reactions never rebuild its row. Messages render code, bold, links and @mentions.
Live Dashboard
Cards that refresh at different rates, from 20 times a second down to once a second. Each card is a scope(), and its timer calls update() with that card's id, so a tick evaluates only that card. Every dynamic value is counted on screen: switch to a plain update() and the clock is evaluated about a hundred times a second to change once.
Pixel Editor
The picture is one plain array of 1024 color strings, and each cell reads its color from it. A stroke writes into the array and calls update(); when it ends, the editor keeps a copy with slice(). Undo, redo and every step in the history list() put an older array back: no store, no immutable data.
Snake
A game loop is a timer that calls step() on plain objects, then update() once per tick. The snake is a list() of its cell objects, and each tick the tail object becomes the new head, so one element moves and none is built: the segments-built count only goes up when the snake eats. Food pops in with a keyframes() animation.
Step Sequencer
A library that owns its own clock. Web Audio books every note ahead on its own timeline, and the pattern is a plain 2D array of booleans that the grid flips and the scheduler reads, so a click is heard on the next pass. The playhead updates only its scope() when the audible step changes. Audio starts on the first Play and closes in the mount cleanup, so leaving the example stops the sound.
Locale Switcher
Every label is a static value, written as in a one-language app, so update() never reads it again: cart clicks refresh only quantities and totals. Switching the language calls forceUpdate() on this tree, which runs the component again and patches the same elements, lang and dir included. Money, plurals, dates and lists come from Intl, and the cart and a typed coupon survive the switch.
Theme Editor
A small component library: createCss() names the tokens and variants() builds buttons, badges, cards, inputs, alerts and switches from them. The tokens are CSS variables, so every class compiles once. Each control writes a plain theme object and calls update(), which rewrites the text of one style element.