Getting Started

Build your first Nounjs application in minutes

How Nounjs Works

Understanding the .noun file compile process

Nounjs uses single-file components (.noun files) that combine your template and logic. The CLI compiles these into standard JavaScript classes that the browser can run.

Step Source Output
Write src/pages/*.noun -
Compile src/pages/*.noun src/compiled/*.js
Import - from './src/compiled/*.js'

Important: Import Paths

Always import from ./src/compiled/*.js, not from ./src/pages/*.noun. The browser runs the compiled JavaScript, not the source .noun files.

Why Compile?

Browsers can't natively understand .noun files. The compile step transforms the single-file component format into a standard ES6 class that extends Component. This keeps your source clean while producing optimized output.

Prerequisites

Everything you need before getting started

Recommended: Bun Runtime

Nounjs is optimized for Bun - a fast JavaScript runtime that serves as a drop-in replacement for Node.js.

  • Install Bun: curl -fsSL https://bun.sh/install | bash
  • Or use Node.js 18+ with npm/pnpm/yarn

Quick Install

Create a new project with a single command

Terminal
# With Bun (recommended)
bunx @noundryfx/nounjs create my-app

# Or with npm
npx @noundryfx/nounjs create my-app

1 Nounjs Tailwind (Default)

Custom Tailwind-based component classes with noun- prefix.

bunx @noundryfx/nounjs create my-app
# or: bunx @noundryfx/nounjs create my-app --tailwind

2 Basecoat UI

Basecoat UI - shadcn/ui-inspired component library.

bunx @noundryfx/nounjs create my-app --basecoat
KEY FEATURE

Scaffold from OpenAPI

Already have an API? Generate a complete admin UI in seconds.

Point at any OpenAPI spec, get a full working UI

The scaffold command parses your OpenAPI/Swagger spec and generates a complete dashboard with list, detail, and form pages for every resource. Includes login page and auth guards auto-detected from securitySchemes. Perfect for rapid prototyping or building internal tools.

# Generate from any OpenAPI endpoint
noun scaffold https://api.example.com/openapi.json

# Or from a local swagger file
noun scaffold ./swagger.json --name "Admin Dashboard"

# Try it with the Pet Store demo API
noun scaffold https://petstore.swagger.io/v2/swagger.json --name "Pet Store"

API Client

Full client with all endpoints

Authentication

Login, OAuth, JWT, API keys

List Pages

Search, sort, pagination

Detail Views

Single item displays

Forms

Create/edit with validation

Common OpenAPI Endpoints by Framework

.NET

/openapi/v1.json

FastAPI

/openapi.json

Express

/api-docs

Spring

/v3/api-docs

Rails

/swagger_doc.json

Step-by-Step Guide

From zero to running application

1

Create Your Project

Run the CLI to scaffold a new Nounjs project.

bunx @noundryfx/nounjs create my-app
cd my-app
2

Install Dependencies

Install the project dependencies.

bun install
# or: npm install
3

Build & Start Development

Build CSS/JS and start the development server with hot reload.

bun run dev
  _   _                       _ ____
 | \ | | ___  _   _ _ __     | / ___|
 |  \| |/ _ \| | | | '_ \ _  | \___ \
 | |\  | (_) | |_| | | | | |_| |___) |
 |_| \_|\___/ \__,_|_| |_|\___/|____/
 v0.9.31

info Starting development server...
done Compiled 10 components in 28ms
done dist/styles.css (57.7kb) in 1067ms
done Initial build complete in 1217ms
4

Open Your App

Open your browser to http://localhost:3000

Your Nounjs app is now running with:

  • Hot reload on file changes
  • Automatic CSS compilation
  • Live browser refresh

Project Structure

Understanding your new Nounjs project

Project Structure
my-app/
├── index.html           # Entry HTML file
├── app.js               # Main application code
├── noun.config.json     # Nounjs configuration
├── tailwind.config.js   # Tailwind CSS configuration
├── package.json         # Dependencies and scripts
├── src/
│   ├── pages/           # Place your .noun files here
│   ├── compiled/        # Generated JS from .noun files
│   └── styles/
│       └── globals.css  # Your Tailwind + custom CSS
└── dist/
    ├── noun.esm.js      # Nounjs runtime (included)
    ├── router.esm.js    # Router module
    ├── styles.css       # Built CSS output
    └── app.js           # Bundled JavaScript output

Key Files

  • app.js - Your main application entry point
  • src/pages/ - Single-file .noun components
  • src/styles/globals.css - Your custom CSS and Tailwind imports
  • noun.config.json - Project configuration

All Available Commands

Complete reference for development and production

Command Description
bun run dev Build CSS + JS, start server with watch
bun run compile Compile .noun files to .js
bun run build Full production build (CSS + JS)
bun run build:css Build Tailwind CSS only
bun run bundle Bundle app.js for production
bun run watch:css Watch and rebuild CSS on changes
bun run serve Start static file server
noun scaffold <url> Generate complete UI from OpenAPI spec
noun publish Deploy to nounjs.app hosting

Your First Component

Two ways to create components in Nounjs

1 JavaScript Component

Edit app.js directly:

app.js
import { Component, mount } from './build/noun.esm.js'

class HelloWorld extends Component {
  template = `
    <div class="p-8 max-w-md mx-auto">
      <h1 class="text-2xl font-bold mb-4">
        Hello { name }!
      </h1>
      <input
        type="text"
        class="input mb-4"
        placeholder="Enter your name"
        :model="name"
      />
      <button @click="greet" class="btn">
        Greet
      </button>
    </div>
  `

  name = 'World'

  greet() {
    alert(\`Hello, \${this.name}!\`)
  }
}

mount('#app', HelloWorld)

2 Single-File Component (.noun)

Create src/pages/hello.noun:

src/pages/hello.noun
<template>
  <div class="p-8 max-w-md mx-auto">
    <h1 class="text-2xl font-bold mb-4">
      Hello { name }!
    </h1>
    <input
      type="text"
      class="input mb-4"
      placeholder="Enter your name"
      :model="name"
    />
    <button @click="greet" class="btn">
      Greet
    </button>
  </div>
</template>

<script>
export default {
  name: 'World',

  greet() {
    alert(\`Hello, \${this.name}!\`)
  }
}
</script>

Using Single-File Components

After creating a .noun file, compile and import it:

# Compile .noun files
bun run compile
// In app.js
import { Hello } from './src/compiled/hello.js'
import { mount } from './build/noun.esm.js'

mount('#app', Hello)

Child Components

Register once, use everywhere

Nounjs uses a global component registry. Register child components once in app.js, then use them anywhere in your templates without imports.

app.js - Register components at startup
import { mount, registerComponent } from './build/noun.esm.js'

// Import and register child components
import { UserCard } from './src/compiled/components/UserCard.js'
import { StatusBadge } from './src/compiled/components/StatusBadge.js'

registerComponent('user-card', UserCard)
registerComponent('status-badge', StatusBadge)

// Mount your app - child components auto-discovered
mount('#app', App)
Any .noun file - Use without imports
<template>
  <div>
    <user-card :user="selectedUser" @delete="handleDelete"></user-card>
    <status-badge :status="item.status"></status-badge>
  </div>
</template>

Tag Names

UserCard → <user-card>

Props

:prop="expr" for dynamic values

Events

@event="handler" to listen

Adding Routes

Set up client-side navigation

app.js
import { createRouter } from './build/router.esm.js'
import { mount } from './build/noun.esm.js'
import { Home } from './src/compiled/home.js'
import { About } from './src/compiled/about.js'
import { User } from './src/compiled/user.js'

const router = createRouter({ mode: 'hash' })

router
  .route('/', () => mount('#app', Home))
  .route('/about', () => mount('#app', About))
  .route('/users/:id', (to) => mount('#app', User, { id: to.params.id }))
  .start()

Hash Mode (Default)

URLs like #/users/123

  • Works without server config
  • Best for static hosting
  • No 404 issues on refresh

History Mode

Clean URLs like /users/123

  • Requires server SPA fallback
  • Better for SEO
  • Use mode: 'history'

Generate Components

Use the CLI to scaffold components quickly

CLI Commands
# Generate a basic component
noun g component Button

# Generate different page types
noun g page Dashboard        # Basic page
noun g page Users list       # List/grid page with search
noun g page Products grid    # NounTable data grid
noun g page UserEdit form    # Create/edit form page
noun g page UserDetail detail # Detail view page
noun g page Login login      # Login page

Building for Production

Prepare your app for deployment

Terminal
# Full production build
bun run build
# or: noun prod

This will:

  1. Copy latest Nounjs runtime to your project
  2. Compile .noun files to JavaScript
  3. Build and minify Tailwind CSS
  4. Bundle and minify JavaScript with source maps

Deploy to nounjs.app

Deploy your app with a single command:

noun publish my-app

Your app will be live at https://my-app.nounjs.app

NEW

Enable DevTools

Built-in visual debugging panel for component inspection

Add to Your App

app.js
import { enableDevTools } from './build/noun.esm.js'

// Enable DevTools (development only)
if (location.hostname === 'localhost') {
  enableDevTools()
}

DevTools Features

  • Component Tree - View all mounted components
  • State Inspector - View and edit state live
  • Event Log - Track lifecycle events
Toggle with Ctrl+Shift+D
NEW

VS Code Extension

AI-powered development with real-time diagnostics and instant deployment

Installation

Terminal
# Install from VSIX
code --install-extension nounjs-0.9.12.vsix

# Or search "Nounjs" in VS Code Extensions

AI Features

  • Cmd+Shift+G AI Generate - Describe a component in plain English
  • Cmd+Shift+I AI Inline - Generate code from magic comments
  • Cmd+Shift+P Command Palette - Run any noun CLI command

Extension Features

Real-Time Diagnostics

Catches errors as you type, detects React patterns and suggests Nounjs equivalents

Component IntelliSense

Autocomplete for 36+ built-in components with prop suggestions

49 Smart Snippets

AI-optimized templates including full CRUD pages, dashboards, auth flows

One-Click Deploy

Publish to nounjs.app without leaving the editor

NEW

TypeScript Support

First-class TypeScript in .noun files

src/pages/user-list.noun
<template>
  <div :for="user of users">
    { user.name } - { user.role }
  </div>
</template>

<script lang="ts">
interface User {
  id: number
  name: string
  role: 'admin' | 'user'
}

export default {
  users: [] as User[],

  async mounted(): Promise<void> {
    this.users = await api.getUsers()
  }
}
</script>

How It Works

Add lang="ts" to your script tag. Nounjs uses Bun's native transpiler for fast compilation. In environments without Bun, it falls back to regex-based type stripping.

REFERENCE APP

Nounjs Starter

A complete reference application demonstrating all core features

Features Demonstrated

Global Stores
$watchStore
Transitions
VirtualList
Named Slots
Router Guards
API Services
Toast Notifications

Key Files to Study

app.js - Router, sharedProps
src/lib/store.js - Auth + Theme stores
src/pages/transitions.noun - Animation demo
src/pages/virtuallist.noun - 10K+ items
src/components/themeswitcher.noun - $watchStore
Clone and run the starter
# Clone the starter app
git clone https://github.com/noundry/nounjs-starter.git
cd nounjs-starter

# Install and run
bun install
bun run dev

# Open http://localhost:3000

The sharedProps Pattern

The starter demonstrates passing services to all pages via a shared props object. This keeps components loosely coupled and testable.

const sharedProps = {
  auth: authService, authStore, themeStore, api: apiService,
  router, utils, validators, toast: toastService,
  transitions: { transitionEnter, transitionLeave },
  createVirtualList
}

mount('#app', Dashboard, sharedProps)  // All pages get these

Next Steps