Examples
Practical examples. Live demos.
Explore small Nuclo patterns with interactive previews and source code beside each behavior.
Counter
Mutate state, then call update(). The dynamic text refreshes.
0
COUNT
Counter.ts
import 'nuclo' let count = 0 export function Counter() { return div( p(() => count), p("COUNT"), button("-", { onClick: () => { count--; update() } }), button("Reset", { onClick: () => { count = 0; update() } }), button("+", { onClick: () => { count++; update() } }), ) }
Todo List
Use list() for repeated items. Call update() after each mutation.
No tasks yet.
0 of 0 remaining
TodoList.ts
import 'nuclo' interface Todo { id: number text: string done: boolean } let todos: Todo[] = [] let filter: "all" | "active" | "done" = "all" let text = "" let nextId = 1 function visible() { if (filter === "active") return todos.filter((t) => !t.done) if (filter === "done") return todos.filter((t) => t.done) return todos } function addTodo() { if (!text.trim()) return todos.push({ id: nextId++, text, done: false }) text = "" update() } export function TodoList() { return div( input( { placeholder: "Add a task..." }, { onInput: (event) => { text = (event.target as HTMLInputElement).value }, }, ), button("Add", { onClick: addTodo }), div( button("All", { onClick: () => { filter = "all"; update() } }), button("Active", { onClick: () => { filter = "active"; update() } }), button("Done", { onClick: () => { filter = "done"; update() } }), ), ul( list( () => visible(), (todo) => li( input( { type: "checkbox", checked: () => todo.done }, { onChange: () => { todo.done = !todo.done; update() } }, ), span(() => todo.done ? todo.text + " done" : todo.text), button("x", { onClick: () => { todos = todos.filter((item) => item.id !== todo.id) update() } }), ), ), when(() => visible().length === 0, div("No tasks yet.")), ), p(() => `${todos.filter((t) => !t.done).length} of ${todos.length} remaining`), ) }
Search Filter
Filter an array with plain JavaScript. Render the result with list().
AC
Alice Chen
alice@example.com
BS
Bob Smith
bob@example.com
CD
Charlie Davis
charlie@example.com
DP
Diana Park
diana@example.com
SearchFilter.ts
import 'nuclo' const users = [ { name: "Alice Chen", email: "alice@example.com", initials: "AC" }, { name: "Bob Smith", email: "bob@example.com", initials: "BS" }, { name: "Charlie Davis", email: "charlie@example.com", initials: "CD" }, { name: "Diana Park", email: "diana@example.com", initials: "DP" }, ] let query = "" function results() { const q = query.toLowerCase() if (!q) return users return users.filter((user) => user.name.toLowerCase().includes(q) || user.email.toLowerCase().includes(q) ) } export function SearchFilter() { return div( input( { placeholder: "Search users..." }, { onInput: (event) => { query = (event.target as HTMLInputElement).value update() }, }, ), div( list( () => results(), (user) => div( div(user.initials), div(user.name), div(user.email), ), ), when(() => results().length === 0, div("No users found.")), ), ) }
Styling
Use css() for classes. Use cx() for small conditional changes.
css() creates the base class. cx() adds the selected class only when state changes.
Styling.ts
import 'nuclo' const { css, cx } = createCss({ colors: { primary: "#ff3f00", border: "#e5e7eb", text: "#1f2937", }, }) const baseButton = css("content-examples-baseButton", { px: 14, py: 9, rounded: 6, border: "1px solid", borderColor: "border", color: "text", cursor: "pointer", }) const selectedButton = css("content-examples-selectedButton", { bg: "primary", color: "white", borderColor: "primary", }) let selected = false export function StyledButton() { return button( () => cx(baseButton, selected && selectedButton), () => selected ? "Selected" : "Select", { onClick: () => { selected = !selected; update() } }, ) }
Styling
Styling basics
A short set of styling examples: create a class, compose a class, and use a tiny theme.
css()
Create a class from one typed style object.
Simple card
One style object returns one reusable class.
css.ts
const card = css("pages-examples-styling-gallery-card", { p: 16, rounded: 8, border: "1px solid", borderColor: "border", bg: "surface", color: "text", }) function Card() { return div(card, "Simple card") }
cx()
Compose classes conditionally. Later styles win.
cx() adds the selected class.
cx.ts
const baseButton = css("pages-examples-styling-gallery-baseButton", { px: 14, py: 9, rounded: 6, border: "1px solid", borderColor: "border", }) const selectedButton = css("pages-examples-styling-gallery-selectedButton", { bg: "primary", color: "white", borderColor: "primary", }) let selected = false function Button() { return button( () => cx(baseButton, selected && selectedButton), () => selected ? "Selected" : "Select", { onClick: () => { selected = !selected; update() } }, ) }
createCss()
Define a small theme and use its tokens.
Theme tokens
Resize above 520px to use the sm screen rule.
createCss.ts
const { css } = createCss({ colors: { primary: "#ff3f00", surface: "#fff7ed", border: "#ffd7c2", }, screens: { sm: "(min-width: 520px)", }, }) const box = css("pages-examples-styling-gallery-box", { p: 12, bg: "surface", borderColor: "border", sm: { p: 20, borderColor: "primary" }, })