@nhealth/nutils
v0.0.3
Published
Shared Nuxt.js v4 module with components, composables, and utilities
Maintainers
Readme
nutils
A comprehensive Nuxt v4 module providing shared components, composables, utilities, and a component-based router for nhealth.org packages.
✨ Features
- 🎨 Auto-registered Components - Use components without explicit imports
- 🔧 Auto-imported Composables - Access composables anywhere in your Nuxt app (useComponentRouter, useConfirmModal)
- 🛠️ Utility Functions - Common utility functions auto-imported
- 🧭 Component-based Routing - Dynamic component rendering with query/hash/memory routing modes
- 📊 Pre-built UI Components - StatCard, StatCounter, LiveIndicator, ConfirmModal, and more
- ⚡ Tailwind + Nuxt UI - Modern styling with Tailwind CSS and Nuxt UI v4
- 📱 Fully Responsive - Mobile-first components
- 🌙 Dark Mode Support - All components support light and dark modes
- 📦 TypeScript Support - Full TypeScript support with type definitions
- ⚡ Nuxt 4 Compatible - Built for Nuxt v4
🚀 Quick Setup
1. Install the module
npm install @nhealth/nutils2. Add to nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nhealth/nutils'
]
})3. (Optional) Add Nuxt UI and Tailwind for full styling
If you want to use the styled components with Nuxt UI and Tailwind CSS:
npm install @nuxt/ui tailwindcssThen add to nuxt.config.ts:
export default defineNuxtConfig({
modules: [
'@nuxt/ui',
'@nhealth/nutils'
],
colorMode: {
preference: 'light'
}
})That's it! You can now use all components, composables, and utilities ✨
📚 Documentation
Components
StatCard
A flexible stat display card with multiple variants and optional descriptions.
<template>
<NUtilsStatCard
label="Total Users"
:value="42500"
icon="i-heroicons-users-20-solid"
variant="primary"
description="Active this month"
/>
</template>Props:
label(string, required) - Label textvalue(number | string, required) - The value to display (numbers are formatted: 1M, 1K, etc.)icon(string, optional) - Icon name (Heroicons compatible)description(string, optional) - Additional description textvariant(string, default: 'gray') - Color variant:'gray' | 'primary' | 'success' | 'warning' | 'error' | 'info'trend(string, default: 'neutral') - Trend indicator:'up' | 'down' | 'neutral'
StatCounter
Compact inline counter for quick status displays.
<template>
<NUtilsStatCounter
label="Pending"
:count="12"
color="warning"
/>
</template>Props:
label(string, required) - Label textcount(number, optional) - Counter valuecolor(string, default: 'neutral') - Color variant:'neutral' | 'primary' | 'success' | 'warning' | 'error' | 'info'
LiveIndicator
Status indicator for connection, system, or service status.
<template>
<NUtilsLiveIndicator status="connected" />
<NUtilsLiveIndicator status="reconnecting" />
<NUtilsLiveIndicator status="offline" />
</template>Props:
status(string, default: 'offline') - Status:'connected' | 'reconnecting' | 'offline'
ComponentRouter
A slot-based component for dynamic component rendering with routing capabilities.
<template>
<NUtilsComponentRouter
v-slot="{ component }"
:routes="routes"
base="page"
mode="query"
>
<component :is="component" />
</NUtilsComponentRouter>
</template>
<script setup>
const routes = {
'/home': () => import('./pages/Home.vue'),
'/about': () => import('./pages/About.vue'),
'/contact': () => import('./pages/Contact.vue'),
}
</script>Props:
routes(Record<string, Component | AsyncComponentLoader>, required) - Route definitionsbase(string, default: 'fp') - Query/hash parameter namemode(string, default: 'query') - Routing mode:'query' | 'hash' | 'memory'initial(string, optional) - Initial route pathdebug(boolean, default: false) - Enable debug logging
Slot Props:
component- Current component to renderroute- Current route object with path, params, and querypush- Function to navigate to a route
ComponentShell
Layout component with integrated navigation and content area.
<template>
<NUtilsComponentShell
orientation="vertical"
:items="navigationItems"
:pageOffset="0"
>
<div class="p-4">
<!-- Content goes here -->
</div>
</NUtilsComponentShell>
</template>
<script setup>
const navigationItems = [
[
{ label: 'Home', path: '/', icon: 'i-heroicons-home-20-solid' },
{ label: 'About', path: '/about', icon: 'i-heroicons-information-circle-20-solid' },
]
]
</script>Props:
orientation(string, default: 'horizontal') - Layout:'horizontal' | 'vertical'items(NavigationMenuItem[][], optional) - Navigation itemsactiveMatch(string, default: 'prefix') - Active match mode:'exact' | 'prefix'pageOffset(string | number, default: 0) - Height offset for container (e.g., "4rem", 64)
Slots:
leading- Additional content above navigationtrailing- Additional content below navigation- Default slot - Main content area
ConfirmModal
Modal dialog for requesting user confirmation with optional validation gates.
<template>
<NUtilsConfirmModal />
<UButton @click="handleDelete">Delete Item</UButton>
</template>
<script setup>
const confirm = useConfirmModal()
async function handleDelete() {
const result = await confirm({
title: 'Delete Item',
description: 'This action cannot be undone.',
dangerous: true,
icon: 'i-heroicons-trash-20-solid',
iconColor: 'error',
confirmLabel: 'Delete',
cancelLabel: 'Cancel',
})
if (result.confirmed) {
// Handle deletion
}
}
</script>Configuration Options:
title(string) - Modal titledescription(string) - Description texttext(string) - Alternative to descriptionitems(string[]) - Bullet list itemswarning(string) - Warning messageicon(string) - Icon nameconfirmLabel(string, default: 'Confirm') - Confirm button labelcancelLabel(string, default: 'Cancel') - Cancel button labeldangerous(boolean) - Style for destructive actionsrequireInputEquals(string) - Require typed confirmationinputPlaceholder(string) - Placeholder for input fieldrequireCheckbox(boolean) - Require checkbox confirmationcheckboxLabel(string) - Checkbox labelconfirmColor(string) - Button coloriconColor(string) - Icon color variant
Composables
useComponentRouter
Dynamic component routing without Nuxt's file-based routing.
<script setup>
const { component, route, push, makePath } = useComponentRouter({
routes: {
'/dashboard': () => import('./Dashboard.vue'),
'/users': () => import('./Users.vue'),
'/users/:id': () => import('./UserDetail.vue'),
},
mode: 'query',
base: 'view',
initial: '/dashboard'
})
const goToUser = (id) => {
push(`/users/${id}`)
}
</script>Options:
routes(Record<string, Component | AsyncComponentLoader>) - Route definitionsmode('query' | 'hash' | 'memory') - Routing modebase(string) - Query/hash parameter nameinitial(string) - Initial routedebug(boolean) - Enable debug logging
Returns:
component- Current component (ShallowRef<Component | null>)route- Current route info (ShallowRef)push(path)- Navigate to pathreplace(path)- Replace current routemakePath(pattern, params)- Build path from patternmakeHref(pattern, params)- Build href from patternpushTo(pattern, params)- Navigate with patternreplaceTo(pattern, params)- Replace with patternhooks- Navigation hooks
useConfirmModal
Modal confirmation dialog management.
<script setup>
const confirm = useConfirmModal({
confirmLabel: 'Yes',
cancelLabel: 'No'
})
const result = await confirm({
title: 'Confirm?',
description: 'Are you sure?'
})
if (result.confirmed) {
// Handle confirmation
}
</script>Utilities
formatDate
Format dates to readable strings.
const date = formatDate(new Date())
// Output: "January 8, 2026"
const date = formatDate(new Date(), 'de-DE')
// Output: "8. Januar 2026"formatNumber
Format numbers with locale-specific separators.
const number = formatNumber(1234567.89)
// Output: "1,234,567.89"
const number = formatNumber(1234567.89, 'de-DE')
// Output: "1.234.567,89"truncate
Truncate strings to maximum length.
const text = truncate('This is a long text', 10)
// Output: "This is..."
const text = truncate('This is a long text', 10, '→')
// Output: "This is→"🎨 Setup with Nuxt UI + Tailwind
For a complete styled experience, follow these steps:
1. Install dependencies
npm install @nuxt/ui @nuxtjs/tailwindcss2. Configure nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxt/ui',
'@nhealth/nutils'
],
colorMode: {
preference: 'light'
},
tailwindcss: {
exposeConfig: true
}
})3. Create tailwind.config.ts
import type { Config } from 'tailwindcss'
import defaultTheme from 'tailwindcss/defaultTheme'
export default {
theme: {
extend: {
fontFamily: {
sans: ['Inter var', ...defaultTheme.fontFamily.sans]
}
}
}
} satisfies Config4. Create app.vue
<template>
<div class="min-h-screen bg-slate-50 dark:bg-slate-900">
<NuxtPage />
</div>
</template>5. Create CSS entry point app.css
@tailwind base;
@tailwind components;
@tailwind utilities;🔧 Development
Setup
# Install dependencies
npm install
# Generate type stubs
npm run dev:prepare
# Develop with the playground
npm run dev
# Build the playground
npm run dev:build
# Run linting
npm run lint
# Run tests
npm run test
# Run type checking
npm run test:typesAdding New Features
Components
Add .vue files to src/runtime/app/components/ - they'll be auto-registered with the NUtils prefix.
<!-- src/runtime/app/components/MyComponent.vue -->
<template>
<div><!-- Your component --></div>
</template>
<script setup lang="ts">
// Your script
</script>Usage:
<NUtilsMyComponent />Composables
Add .ts files to src/runtime/app/composables/ - they'll be auto-imported.
// src/runtime/app/composables/useMyComposable.ts
export function useMyComposable() {
// Your composable logic
}Usage:
const myComposable = useMyComposable()Utilities
Add .ts files to src/runtime/shared/ - they'll be auto-imported.
// src/runtime/shared/myUtil.ts
export function myUtil(input: string): string {
return input.toUpperCase()
}Usage:
const result = myUtil('hello')📦 Module Options
Configure the module in your nuxt.config.ts:
export default defineNuxtConfig({
modules: [
'@nhealth/nutils'
],
nutils: {
enabled: true // Enable or disable the module
}
})🎯 Playground
The module includes a comprehensive playground at playground/app.vue demonstrating all components and composables. Run npm run dev to explore.
📄 License
MIT
