Nexa Reference
Everything Nexa has, organized as a catalog — just like other frameworks' component reference. Search by name or filter by category; each card leads to a real, functional example.
File-based routing
Every .tsx under src/pages/ is a real route. [slug].tsx captures a dynamic segment; [locale] is the special segment that turns on i18n for that whole branch.
Core and pagesA page, top to bottom
load/paths/seo/schema are literal objects/templates — never executed; nexa-parser recognizes them as fixed patterns and resolves them itself against real data at build/request time. That's why they can't hold logic: no conditionals, no .map(), no functions of your own.
Core and pagesload() — fetching data
A real HTTP GET against NEXA_API_URL + url, with :params substituted by the route's real values. The backend can be any language — Nexa only expects JSON back.
Core and pagespaths() — pre-rendering dynamic routes
Same shape as load, but the backend responds with an array of parameter sets. nexa build generates a real index.html for each entry — plain HTML, with no dependency on the backend still running.
Core and pages<For> — iterating lists
Not a component or an HTML element — a fixed syntactic pattern, just like t("key"). Rust classifies the callback's body once (it's a template) and renders it as real HTML once per array element.
Core and pagesAutomatic active link
An <a href> whose href matches the current route gets aria-current="page" on its own — no conditional to write (a Nexa page has no logic of its own to write one in). data-nexa-match="prefix" turns it into prefix matching, with a segment boundary.
Core and pagesShared layouts
src/layout.tsx, optional, wraps every project page's HTML. It compiles just like any page — this isn't composition: nexa-cli finds the single empty data-nexa-slot and inserts the page's already-rendered HTML there, verbatim.
Core and pagesexport const head
The only thing that actually reaches the document's real <head> (everything else the layout returns ends up inside <body>, via the slot splice). icon/appleTouchIcon/stylesheets/meta — a literal object, same pattern as seo/schema.
Core and pagesHeader with real state: an island in the layout
A direct onClick in src/layout.tsx isn't supported (node ids would collide between the layout and the page). An island is — the client reads specifier/props/strategy from the DOM, with no activation-manifest entry, and survives SPA navigation without remounting.
SEO and i18nseo{}
Per-page title/description/canonical/Open Graph/Twitter card. Each field is a string, a template, or t("...") — never a function. A field that can't resolve gets omitted, never filled in halfway.
SEO and i18nschema{} — real JSON-LD
Resolves to a real <script type="application/ld+json">. type/@type is interchangeable; an explicit @type never gets overwritten.
SEO and i18nAutomatic sitemap.xml and robots.txt
nexa build generates both for every compiled static route. nexa-seo warns (NEXA-SEO-001..) if title/description/canonical is missing, or an image lacks alt — it never blocks the build.
SEO and i18nBasic i18n: t() and [locale]
src/locales/<locale>.json is a flat dictionary. t("home.title") resolves against the current locale's dictionary — no fallback to another language: a missing key gets omitted (in seo) or stays inert in the body.
SEO and i18nInterpolation in t()
t("key", { variable: data.x }) substitutes the matching placeholder inside the dictionary text. nexa build/nexa lint fail with a clear error if a key and its arguments don't match up.
SEO and i18nAutomatic hreflang
<link rel="alternate" hreflang="..."> is generated automatically as long as the route lives under [locale] and there's more than one src/locales/*.json — nothing to write by hand.
Interactive islandsMarking an island
data-nexa-island is a string literal, resolved against nexa.toml [imports] — Rust never opens or interprets the module it points to. The fallback (the div's children) resolves with the same mechanism as any other content: data.*, t(), <For> included.
Interactive islandsThe mount() contract
The module must default-export a mount(el, props) function that optionally returns a cleanup function. You can write it by hand with @nexa/reactivity, or mount a real framework.
Interactive islandsReal Vue inside an island
A real Vue (or other framework) component, with Rust never reading or understanding it — it runs 100% on the client. A Vue Router mounted inside coexists without conflict with Nexa's SPA navigation.
Interactive islandsAn npm library inside an island
Different from [imports]: an island file gets bundled in full with esbuild (--bundle --format=esm), so a normal import at the top resolves just like in any TypeScript project.
Interactive islandsLightweight component model (islands only)
Doesn't apply to Nexa Core pages. Component<P>, mountComponent(), and a ComponentContext that chains children's cleanup to the parent's — no Virtual DOM, exclusively for code inside a native island.
@nexa/ui — Visual componentsButton
nx-btn + a variant (primary/outline). Nothing to declare — nexa build detects the nx-* classes and generates the matching CSS.
@nexa/ui — Visual componentsInput
nx-input. With aria-invalid="true" (which @nexa/forms adds on its own) it already has a red border, nothing extra to declare.
@nexa/ui — Visual componentsCard
nx-card + an optional nx-card-title.
@nexa/ui — Visual componentsTable
nx-table-wrap adds horizontal scroll on small screens; nx-table-zebra alternates row backgrounds.
@nexa/ui — Visual componentsBadge
nx-badge + a variant: primary/success/warning/danger/neutral.
@nexa/ui — Visual componentsAvatar
nx-avatar (a circle, 2.5rem by default) + nx-avatar-sm/-lg. With an <img> inside it crops via object-fit: cover.
@nexa/ui — Visual componentsBreadcrumbs
nx-breadcrumbs (container) + nx-breadcrumbs-link — the "/" between steps is plain CSS (::after), nothing to write by hand. aria-current="page" marks the current step.
@nexa/ui — Visual componentsAlert
nx-alert + a success/warning/danger variant (colored left border). An optional nx-alert-title.
@nexa/ui — Visual componentsDivider
nx-divider (horizontal) / nx-divider-vertical.
@nexa/ui — Visual componentsTooltip
nx-tooltip-content shows on :hover/:focus-within — keyboard accessible, zero lines of JS.
@nexa/ui — Visual componentsProgress
nx-progress-bar needs its width set by hand (fixed, or dynamic via data.*) — Nexa doesn't compute any percentage.
@nexa/ui — Visual componentsSkeleton
nx-skeleton is a block with a shimmer animation; the developer sets whatever width/height it needs.
@nexa/ui — Visual componentsLayout utilities
A small, deliberate set, not a full Tailwind-like utility system: nx-flex/nx-gap-N/nx-grid/nx-grid-cols-N/nx-stack.
@nexa/ui — Visual componentsDark theme
With zero JS, the site already respects the system's prefers-color-scheme. platform.theme.set("dark") lets the user choose explicitly and override the system, persisted with platform.storage().
@nexa/ui — Interactive, no islandDialog
ui.openDialog(el)/ui.closeDialog(el) — trapped focus, Escape closes it, returns focus to the previous element. ui is always available, nothing to declare in [imports].
@nexa/ui — Interactive, no islandDialog stacking
Opening a Dialog while another is already open stacks it on top (correct z-index) and hides the one below from screen readers (aria-hidden) while it's covered.
@nexa/ui — Interactive, no islandui.confirm() / ui.alert()
Confirm before a destructive action, or notify that something was saved, without writing the <div class="nx-dialog"> by hand. Escape in confirm() counts as canceling; in alert(), as accepting.
@nexa/ui — Interactive, no islandDrawer
Same accessibility contract as Dialog, meant for sidebars/side menus instead of a centered box.
@nexa/ui — Interactive, no islandToast / snackbar
ui.notify() — not to be confused with platform.notify() (a real OS notification): this one is ephemeral, inside the page. It stacks with others, auto-closes after 4s.
@nexa/ui — Interactive, no islandTabs
ui.selectTab(event) reads which button was clicked and its data-tab, finds the nearest .nx-tab-group, and does the rest.
@nexa/ui — Interactive, no islandAccordion
ui.toggleAccordionItem(event). With data-exclusive="true" on the container, opening one item closes the rest.
@nexa/ui — Interactive, no islandDropdown
ui.toggleDropdown(event) / ui.selectDropdownOption(event) — closes on an outside click or Escape, without trapping focus (a dropdown doesn't block the rest of the page).
@nexa/ui — Interactive, no islandSorting and filtering a Table
ui.sortTable(event) sorts by the clicked <th>'s column (numeric if both cells are). ui.filterTable(table, query) hides rows whose text doesn't match. Both client-side, no re-fetch.
@nexa/ui — Interactive, no islandReactive page search
ui.createPageSearch(container) filters data-searchable elements with a real @nexa/reactivity Signal underneath. The controller hangs off the <input> itself because every chunk is an isolated module.
@nexa/formsValidation with data-nexa-form
data-nexa-form turns everything else on. Each field needs a name, connected to <p data-nexa-error-for="that-name">. It validates on first blur, and on every change after that.
@nexa/formsCustom messages and automatic classes
data-nexa-message replaces the browser's native message. Automatic classes per field: nx-touched, nx-dirty, nx-invalid, plus aria-invalid.
@nexa/platformplatform.share()
Web: Web Share API. Capacitor: the @capacitor/share plugin. Tauri: not supported (throws).
@nexa/platformplatform.notify()
A real OS-level notification. Web: Notification API (asks for permission). Capacitor: @capacitor/local-notifications.
@nexa/platformplatform.capturePhoto()
Web: getUserMedia + canvas. Capacitor: @capacitor/camera. Returns { dataUrl }.
@nexa/platformplatform.storage() / sessionStorage()
The same get/set/remove contract over localStorage or sessionStorage — the latter lives only as long as the tab does.
@nexa/platformplatform.cache()
Direct Cache API, independent from [pwa.cache] (which lives in the service worker) — for caching something specific from regular code.
@nexa/platformplatform.db()
A minimal wrapper over IndexedDB, not an ORM. Each collection name is its own database — nothing to declare upfront.
@nexa/platformplatform.network
Native Capacitor uses the real @capacitor/network; Web/Tauri use navigator.onLine + the online/offline events. type (wifi/cellular) is Capacitor-only.
@nexa/platformplatform.lifecycle
Native Capacitor uses @capacitor/app (getState/appStateChange); Web/Tauri use document.hidden + visibilitychange — the same signal @capacitor/app's own web branch uses.
@nexa/platformplatform.geolocation
Native Capacitor uses @capacitor/geolocation; Web/Tauri use navigator.geolocation — the same API @capacitor/geolocation's own web branch uses internally.
@nexa/platformplatform.deepLinks
Native Capacitor uses @capacitor/app (getLaunchUrl/appUrlOpen). Web/Tauri: getLaunchUrl() always returns an empty url and onOpen() never fires — that's exactly how @capacitor/app's own web branch behaves.
@nexa/platformplatform.push
Deliberately smaller than the full Capacitor plugin: registration + receiving only. register() returns a discriminated union because Capacitor and Web don't share a registration shape.
@nexa/platformplatform.biometrics
Native Capacitor uses @aparajita/capacitor-biometric-auth. Web/Tauri use real WebAuthn — that plugin's own web branch wasn't replicated because it's a deliberate simulation, not real biometrics.
@nexa/platformplatform.haptics
Native Capacitor uses the real @capacitor/haptics. Web/Tauri use navigator.vibrate — the same API @capacitor/haptics' own web branch uses.
@nexa/reactivitystate() — Signal
.value reads and subscribes; .peek() reads without subscribing. Writing .value fires the effects that read it, batched by microtask.
@nexa/reactivitycomputed()
A ReadonlySignal that recalculates on its own. Chaining computeds works, at a real cost: each hop is one more microtask round-trip.
@nexa/reactivityeffect()
Runs right away, and again every time something it read changes. Returns a function to turn it off.
@nexa/reactivitywatch()
Like effect, but does NOT run when created — only on later changes. Receives the new and the old value.
@nexa/reactivitybindText()
What the compiler automatically generates for {data.x} in a page's body — not something you'd normally write by hand.
@nexa/reactivitymountComponent() — islands only
Doesn't apply to Nexa Core pages. Component<P>, typed props, and chained cleanup — no Virtual DOM.
@nexa/httpcreateApi()
Real get/post/put/delete. A non-2xx status throws HttpError { status, message }.
@nexa/httpquery()
data/loading/error as @nexa/reactivity Signals. cachePolicy: cache-first (default) | network-first | stale-while-revalidate.
@nexa/httpmutation()
The same Signals (data/loading/error) as query(), for an action the user triggers (create, edit, delete).
@nexa/httpconnectSSE()
A thin wrapper over the native EventSource. data is the last message, parsed as JSON when possible.
@nexa/httpconnectSocket()
A wrapper over the native WebSocket. status reflects the real lifecycle; send() serializes objects as JSON automatically.
@nexa/httpReconnection with backoff
reconnect: true (or an object to tweak the defaults) reconnects on its own with exponential backoff + jitter. status passes through "reconnecting" while it tries.
Third parties and vendoringThird-party CSS: a plain <link>
Nexa never processes or understands that CSS, so no special step is needed.
Third parties and vendoringJS with a global build (UMD): a plain <script>
Leaves a global variable — since a chunk copies the handler verbatim, you can use it directly in an onClick, nothing to declare in nexa.toml.
Third parties and vendoringPure ES modules: [imports]
The same mechanism platform/ui use. The chunk detects name. in the handler and prepends the import.
Third parties and vendoringVendoring a real npm package
When it has its own dependencies or ships as CommonJS: install it, write an entry.js, and esbuild --bundle --format=esm into a single file under public/vendor/.
Images, PWA and performanceAutomatically optimized images
No config needed: any static <img src> wider than 480px turns into a <picture> with real AVIF variants at several widths, with width/height/loading="lazy" filled in on their own.
Images, PWA and performancePWA
nexa add pwa adds [pwa] to nexa.toml. nexa build generates a real manifest.webmanifest and sw.js; every page carries the <link rel="manifest"> and the service worker registration on its own.
Images, PWA and performancePerformance budgets
With this declared, nexa build fails (not just warns) if a page goes over — naming exactly what was exceeded.
Images, PWA and performanceTelemetry
Without the explicit endpoint, @nexa/telemetry never loads. With it, every page sends Core Web Vitals (LCP/CLS/INP) and uncaught errors.
Native, deployment and CLITauri (desktop)
Generates a real Windows/macOS/Linux binary, compiled with cargo — the same source code as the web version.
Native, deployment and CLICapacitor (Android/iOS)
Generates a real Android/iOS project. The Android build was verified end to end (a real APK compiled with Gradle); iOS needs Xcode.
Native, deployment and CLIDeploying with nginx
Generates a real deploy/nginx.conf: gzip, security headers, a year-long immutable cache only for hashed files, and a real proxy_pass for dynamic routes without paths.
Native, deployment and CLIThe full CLI
nexa build/preview/dev/lint/test/add/info — lint fails if there are SEO/package warnings; test compiles (a fresh dist/) and runs the project's test runner.
Native, deployment and CLInexa.toml — full reference
Every section is optional except [project]. None of them require package.json or npm.
Native, deployment and CLI@nexa/test
For testing an isolated activation chunk, outside a real browser — mountChunk/getEntry/expectEntry against the real manifest.
No results — try another word, or pick "All" to see everything again.