v1.0 — Nuxt.js edition

Vela — Nuxt Admin Dashboard Template

Thank you for purchasing Vela! This guide covers installation, customization, and the full architecture of the Nuxt.js edition of the template.

Introduction

This is the Nuxt.js edition of Vela — the same Vue 3 component library and ~155-page design as the Vue.js edition, running under Nuxt 4 with full server-side rendering. Built with Vue 3 (<script setup> + TypeScript), Nuxt's file-based router, Tailwind CSS v4, and Vite. It ships with:

  • 10 complete demo dashboards — Analytics, CRM, Ecommerce, Finance, Sales, Marketing, Logistics, Projects, SaaS, and Business Intelligence.
  • ~155 production-ready routes, all server-rendered — full CRUD flows, apps (chat, email, calendar, kanban…), tables, forms, charts, auth flows, settings, reports and utility pages.
  • The same 27 UI components + 9 chart components as the Vue.js edition, shared verbatim.
  • Dark & light themes that render correctly on the very first server-sent byte — no theme flash, no hydration mismatch.
  • No tracking scripts — the template contains no analytics, no external calls except Google Fonts and demo images.

Requirements

  • Node.js 20+ (LTS recommended) — nodejs.org
  • npm 10+ (bundled with Node)
  • Any modern editor — VS Code with the Vue - Official (Volar) extension recommended.
  • A hosting environment that can run a Node.js server (or any platform with Nitro's edge/serverless presets — see Build & deployment).

Installation

Unzip the package, open a terminal inside the vela-nuxt folder, then:

# 1. Install dependencies
npm install

# 2. Start the dev server (http://localhost:3000)
npm run dev

# 3. Type-check
npm run typecheck

# 4. Production build (outputs to .output/)
npm run build

# 5. Preview the production build locally
node .output/server/index.mjs
That's it — there is no database, API keys, or environment configuration required. All demo data is local TypeScript under app/data.

Project structure

vela-nuxt/
├─ nuxt.config.ts          # Nuxt config: components auto-import, Tailwind Vite plugin
├─ public/                 # Static assets, favicon, this documentation
└─ app/                    # Nuxt 4's srcDir (@ and ~ both alias here)
   ├─ assets/css/main.css   # ALL design tokens + Tailwind theme mapping
   ├─ pages/                # Real Nuxt route tree — thin wrapper files only
   ├─ components/
   │  ├─ pages/             # The actual page implementations (one per route)
   │  ├─ ui/                # 27 reusable components (Button, Card, DataTable…)
   │  ├─ charts/             # 9 handcrafted SVG chart components
   │  └─ layout/              # AppShell chrome: Sidebar, Topbar, MobileDrawer…
   ├─ layouts/               # default.vue (app shell), auth.vue
   ├─ composables/           # useTheme, useToast (SSR-safe, see below)
   ├─ data/                  # Local demo data (typed, no backend)
   ├─ lib/                   # Helpers (cn, status)
   └─ router/paths.ts        # Canonical URL manifest for every page
Page implementations live under components/pages/, not pages/. The real pages/ tree is a set of thin wrapper files (<template><AnalyticsDashboardPage /></template>) so Nuxt's flat component auto-import can resolve every page component by filename alone, with zero import statements.

Routing & adding pages

Every URL still lives in one manifest: app/router/paths.ts (identical to the Vue.js edition). To add a page:

1. Register the path

// app/router/paths.ts
reports: {
  root: "/reports",
  weekly: "/reports/weekly",   // ← new
},

2. Create the page implementation

// app/components/pages/reports/WeeklyReportPage.vue
<script setup lang="ts">
// ...
</script>
<template>...</template>

3. Add the thin route wrapper

// app/pages/reports/weekly.vue
<template>
  <WeeklyReportPage />
</template>

4. Add it to the sidebar

// app/components/layout/nav-config.ts — find the group and add a leaf
{ label: "Weekly Report", to: paths.reports.weekly },
Nuxt's file-based router determines the URL from the file's path under app/pages/ — a [id].vue file segment maps to a :id route param, and index.vue maps to its parent folder's own path.

UI & chart components

nuxt.config.ts registers flat, non-prefixed auto-imports for components/{pages,ui,charts,layout}, so every component resolves by its own filename with no import statement needed, anywhere in the app:

<Button variant="primary" size="sm">Save changes</Button>
<DataTable :rows="rows" :columns="columns" />

Highlights: DataTable (generic, sortable, custom per-column cells via named scoped slots keyed by column key), Kanban, Timeline, Modal/Drawer/Popover (each wrapped in <ClientOnly> around a <Teleport to="body"> — see SSR notes), form controls (Input, Select, Textarea, Checkbox, Radio, each using defineModel() for real two-way binding), Skeleton loaders, and AnimatedNumber. A live gallery of every component ships in the app itself at /components.

Charts (components/charts) are dependency-free SVG: area, bar, donut, heatmap, funnel, sparkline, gauge, and Gantt — all consuming the same design tokens, no charting library required. Any id generated at render time (e.g. gradient ids) uses Vue's SSR-safe useId(), never Math.random().

Colors & theming

The entire look of Vela is controlled from one file: app/assets/css/main.css. It defines raw CSS variables for dark (:root) and light (:root[data-theme="light"]), then maps them into Tailwind utilities via the @theme block — identical token set to every other Vela edition.

Changing the accent color

Update --acc, --acc-2, and --acc-soft in both the dark and light blocks. Every button, chart, link, and gradient updates instantly — components only ever reference tokens, never raw hex values.

Dark / light mode

app/composables/useTheme.ts reads and writes the theme via Nuxt's useCookie() (not localStorage) and applies data-theme to <html> via useHead(). This is what lets the correct theme render on the first server-sent byte — see SSR & hydration notes for why this matters. Use it anywhere:

const { theme, toggleTheme } = useTheme();

State management

Vela intentionally ships with no external state library — no Pinia, no Vuex — so you can drop in whatever your product uses. State is organized as:

  • Global UI stateuseTheme and useToast, both built on Nuxt's useState() (request-scoped, SSR-safe) rather than a plain module-level ref, so concurrent requests on the server never leak state between users.
  • Page state — plain ref/computed inside each page (filters, pagination, modals…).
  • Demo data — typed constants in app/data/*.ts. Replace these with real API calls (e.g. via useFetch/useAsyncData); page components consume plain arrays/objects, so swapping the data source is straightforward.

SSR & hydration notes

This edition renders on the server by default (ssr: true). A few patterns in the codebase exist specifically to keep server-rendered HTML and the client's first render in agreement, and are worth knowing if you extend the app:

Never read browser-only state during render

localStorage, window, and document don't exist on the server. Reading them at component setup time (rather than inside onMounted() or an event handler) makes the server render one thing and the client render another — Vue then reports a hydration mismatch. This is exactly what the theme composable used to do during development; it now sources the theme from useCookie() instead, which is visible to the server on the incoming request.

Never generate a random value at render time

Math.random(), crypto.randomUUID(), and bare Date.now() called during setup/render produce a different value on the server than on the client's re-render. Use Vue's useId() for any id that needs to be unique but stable across SSR and hydration (see AreaLineChart.vue's gradient id for a worked example). It's fine to call these inside a click handler or other user-triggered function — only render-time calls are unsafe.

Wrap body-teleporting overlays in <ClientOnly>

Modal, Drawer, ToastHost, and CommandPalette all use <Teleport to="body">. Wrapping them in <ClientOnly> is a zero-cost safeguard — they're closed by default anyway, so nothing is visible pre-hydration either way.

If you introduce a new global composable or a new component that teleports to <body>, follow the same patterns: request-scoped state via useState(), no direct DOM/storage reads outside onMounted/handlers, and <ClientOnly> around the teleport.

Other framework versions

Vela ships as one multi-framework product. If this Nuxt.js edition isn't the right fit for your stack, the same ~155-page design and demo data are also available as:

  • Vue.js — this same component library, client-rendered only (no Node.js server to run in production).
  • React and Next.js editions.
  • Static HTML/CSS/vanilla-JS — no build step, no framework at all.
  • Laravel, Django, and ASP.NET editions, generated from the static HTML export for teams standardized on those backends.

Each edition is a separate downloadable package with its own bundled documentation.

Build & deployment

npm run build produces a Nitro server bundle in .output/. Unlike the Vue.js (SPA) edition, this is a real server — run it with node .output/server/index.mjs, or target one of Nitro's built-in deployment presets for your platform:

TargetHow
Node.js server (any host/VPS)Default build output — node .output/server/index.mjs
Vercel / NetlifyAuto-detected by the platform's Nuxt integration — no config needed
Static hosting (no SSR)nuxt generate pre-renders every route to static HTML if you don't need per-request SSR

See the official Nuxt deployment docs for the full list of Nitro presets (Cloudflare, Deno, AWS Lambda, and more).

Credits & licenses

All third-party software used by Vela is free, open-source, and licensed for commercial use:

PackagePurposeLicense
NuxtApplication framework / SSRMIT
Vue 3UI runtimeMIT
Tailwind CSS (+ Vite plugin)StylingMIT
ViteBuild toolMIT
TypeScriptLanguage (dev only)Apache-2.0

Fonts

FontSourceLicense
Plus Jakarta SansGoogle FontsSIL Open Font License 1.1
JetBrains MonoGoogle FontsSIL Open Font License 1.1

Images & icons

  • All icons and illustrations are hand-drawn inline SVG created for this template — no icon font or icon library is bundled.
  • Demo product photos are hot-linked from Unsplash (free for commercial use, no attribution required). They are demo placeholders — replace them with your own product imagery.
No tracking: the template contains zero analytics, telemetry, or tracking scripts of any kind.

Support

If you have questions not covered here, please reach out through the item's Comments tab or the support contact listed on our ThemeForest profile. Please include your purchase code and a description of the issue.

Reminder: a regular license covers one end product. Redistribution or resale of the template source requires an extended license — see the ThemeForest license terms.

© Vela. All rights reserved.