Components
The Nuxt Users module provides several Vue components to help you quickly implement authentication and user management features in your application. These components are designed to work out of the box with minimal configuration while offering extensive customization options.
Available Components
Component | Purpose |
---|---|
NUsersLoginForm | Complete login form with validation and forgot password functionality |
NUsersLogoutLink | Simple logout link with confirmation |
NUsersResetPasswordForm | Password reset form for users with reset tokens |
NUsersList | Paginated list of users with management actions |
NUsersUserCard | Individual user display card with edit/delete actions |
NUsersUserForm | Form for creating and editing user accounts |
NUsersPasswordStrengthIndicator | Displays real-time password strength feedback (uses usePasswordValidation composable) |
Authentication Components
NUsersLoginForm
A complete login form with built-in validation, error handling, and forgot password functionality.
Basic Usage
<script setup>
const handleLoginSuccess = (user) => {
console.log('Login successful:', user)
// Redirect user or update UI
}
const handleLoginError = (error) => {
console.log('Login failed:', error)
// Show error message to user
}
</script>
<template>
<NUsersLoginForm
@success="handleLoginSuccess"
@error="handleLoginError"
/>
</template>
Customization Options
Props
Prop | Type | Default | Description |
---|---|---|---|
redirectTo | string | '/' | Where to redirect after successful login |
Events
Event | Payload | Description |
---|---|---|
success | User | Emitted when login is successful |
error | string | Emitted when login fails |
Customization Slots
The login form provides several slots for customization:
<NUsersLoginForm>
<!-- Custom header -->
<template #header>
<div class="custom-header">
<h2>Welcome Back!</h2>
<p>Sign in to your account</p>
</div>
</template>
<!-- Custom submit button -->
<template #submit-button>
<FormKit type="submit" class="custom-button">
Sign In
</FormKit>
</template>
<!-- Custom footer with additional links -->
<template #footer>
<div class="login-footer">
<p>Don't have an account? <a href="/signup">Sign up</a></p>
</div>
</template>
</NUsersLoginForm>
NUsersLogoutLink
A simple logout component that handles user logout with optional confirmation.
Basic Usage
<script setup>
const handleLogoutSuccess = () => {
console.log('Logout successful')
// Handle post-logout actions
}
const handleLogoutError = (error) => {
console.log('Logout error:', error)
// Handle logout errors
}
</script>
<template>
<NUsersLogoutLink
@success="handleLogoutSuccess"
@error="handleLogoutError"
/>
</template>
Customization Options
Props
Prop | Type | Default | Description |
---|---|---|---|
linkText | string | 'Logout' | Text displayed in the logout link |
redirectTo | string | '/login' | Where to redirect after logout |
confirmMessage | string | 'Are you sure you want to logout?' | Confirmation message |
class | string | undefined | Additional CSS classes |
Examples
<!-- Custom styling and text -->
<NUsersLogoutLink
link-text="Sign Out"
class="custom-logout-btn"
redirect-to="/home"
/>
<!-- No confirmation dialog -->
<NUsersLogoutLink
:confirm-message="null"
link-text="Quick Logout"
/>
NUsersResetPasswordForm
A form component for users to set a new password using a reset token from their email.
Basic Usage
<template>
<NUsersResetPasswordForm />
</template>
This component automatically:
- Reads the
token
andemail
from URL query parameters - Validates password confirmation
- Handles API calls for password reset
- Redirects to login page on success
- Displays error messages
User Management Components
NUsersList
A comprehensive component for displaying and managing users with pagination, search, and customizable display options.
Basic Usage
<template>
<div>
<NUsersList />
</div>
</template>
Advanced Customization
<script setup>
import { ref } from 'vue'
const { updateUser } = useUsers()
const selectedUser = ref(null)
const handleEditClick = (user) => {
selectedUser.value = user
}
const handleUserUpdated = async (userData) => {
selectedUser.value = null
// Update the user in the local state using the composable - optimistic update
if (userData.id) {
updateUser(userData)
}
// call the API to update the user
await $fetch(`/api/nuxt-users/${userData.id}`, {
method: 'patch',
body: userData,
})
}
const handleEdit = (user) => {
selectedUser.value = user
}
const handleDelete = (user) => {
// API call is done by the module
console.log('User deleted:', user)
}
</script>
<template>
<NUsersUserForm
v-if="selectedUser"
:user="selectedUser"
@submit="handleUserUpdated"
/>
<NUsersList
:display-fields="['name', 'email', 'role']"
:field-labels="{ name: 'Full Name', email: 'Email Address', role: 'Access Level' }"
@edit-click="handleEdit"
@delete="handleDelete"
>
<!-- Custom title -->
<template #title>
<h1>Team Members</h1>
</template>
<!-- Custom user display -->
<template #user="{ user, index }">
<div class="custom-user-item">
<div class="user-info">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
<span class="role-badge">{{ user.role }}</span>
</div>
<div class="user-actions">
<button @click="handleEdit(user)">Edit</button>
</div>
</div>
</template>
<!-- Custom pagination -->
<template #pagination="{ pagination, fetchUsers, loading }">
<div class="custom-pagination">
<button
:disabled="loading || !pagination.hasPrev"
@click="fetchUsers(pagination.page - 1)"
>
Previous
</button>
<span>Page {{ pagination.page }} of {{ pagination.totalPages }}</span>
<button
:disabled="loading || !pagination.hasNext"
@click="fetchUsers(pagination.page + 1)"
>
Next
</button>
</div>
</template>
</NUsersList>
</template>
Props and Events
Props
Prop | Type | Default | Description |
---|---|---|---|
displayFields | string[] | ['id', 'name', 'email', 'role', 'created_at'] | Fields to display for each user |
fieldLabels | Record<string, string> | Default labels | Custom labels for fields |
Events
Event | Payload | Description |
---|---|---|
editClick | User | Fired when edit button is clicked |
delete | User | Fired after successful user deletion |
Available Slots
Slot | Props | Description |
---|---|---|
title | - | Custom list title |
loading | { loading: boolean } | Custom loading indicator |
error | { error: string } | Custom error display |
noUsers | - | Content when no users found |
user | { user: User, index: number } | Custom user item display |
pagination | { pagination, fetchUsers, loading } | Custom pagination controls |
Events
Event | Payload | Description |
---|---|---|
editClick | User | Fired when edit button is clicked |
delete | User | Fired after successful user deletion |
NUsersUserCard
Displays individual user information with edit and delete actions. Used internally by NUsersList
but can be used standalone. The edit
and delete
events are emitted when the edit or delete button is clicked. The delete
event is calling the API to delete the user, while the edit
event is just emitting the user object and let the parent component handle the edit action.
Automatic UI Updates
The NUsersList
component follows an event-driven pattern for handling user updates. When a user is edited, the component emits events that the parent can handle to update the local state.
Event Flow:
- User clicks edit →
NUsersUserCard
emitseditClick
NUsersList
forwards the event to parent → Parent receiveseditClick
- Parent shows edit form → User submits changes
- Parent updates local state → UI automatically reflects changes
Example with event-driven updates:
<script setup>
import { ref } from 'vue'
import { useUsers } from 'nuxt-users/composables'
const { users, updateUser } = useUsers()
const editingUser = ref(null)
const handleEdit = (user) => {
editingUser.value = user
}
const handleUserUpdated = (userData) => {
editingUser.value = null
// Update the local state using the composable
if (userData.id) {
updateUser(userData)
}
}
</script>
<template>
<div>
<NUsersUserForm
v-if="editingUser"
:user="editingUser"
@submit="handleUserUpdated"
/>
<NUsersList
@edit-click="handleEdit"
/>
</div>
</template>
Benefits of this approach:
- Loose coupling - Components don't need to know about each other's internal methods
- Event-driven - Clean separation of concerns
- Reusable - Parent can handle events however it wants
- Testable - Easy to test event handling
- Flexible - Parent can implement any update strategy
Basic Usage
<script setup>
const user = {
id: 1,
name: 'Jane Doe',
email: '[email protected]',
role: 'user'
}
const handleEdit = (user) => {
console.log('Edit user:', user)
}
const handleDelete = (user) => {
console.log('User deleted:', user)
}
</script>
<template>
<NUsersUserCard
:user="user"
:index="0"
@edit-click="handleEdit"
@delete="handleDelete"
/>
</template>
Customization
<template>
<NUsersUserCard
:user="user"
:index="0"
:display-fields="['name', 'role']"
:field-labels="{ name: 'User Name', role: 'Access Level' }"
>
<!-- Completely custom card layout -->
<template #userCard="{ user }">
<div class="custom-card">
<div class="user-avatar">
<img :src="user.avatar" :alt="user.name" />
</div>
<div class="user-details">
<h4>{{ user.name }}</h4>
<p>{{ user.email }}</p>
<span class="role">{{ user.role }}</span>
</div>
<div class="user-actions">
<button @click="handleEdit(user)">Edit</button>
<button @click="handleDelete(user)">Delete</button>
</div>
</div>
</template>
</NUsersUserCard>
</template>
NUsersUserForm
A complete form for creating new users or editing existing ones with validation.
Creating New Users
<script setup>
const handleUserCreated = (userData) => {
console.log('New user created:', userData)
// Refresh user list or redirect
}
</script>
<template>
<NUsersUserForm @submit="handleUserCreated" />
</template>
Editing Existing Users
<script setup>
import { ref } from 'vue'
const userToEdit = ref({
id: 1,
name: 'Jane Doe',
email: '[email protected]',
role: 'user'
})
const handleUserUpdated = (userData) => {
console.log('User updated:', userData)
userToEdit.value = null // Close form
}
</script>
<template>
<NUsersUserForm
:user="userToEdit"
@submit="handleUserUpdated"
/>
</template>
Props and Events
Props
Prop | Type | Default | Description |
---|---|---|---|
user | User | null | null | User to edit (null for create mode) |
Events
Event | Payload | Description |
---|---|---|
submit | Partial<User> | Fired after successful create/update |
cancel | - | Fired when cancel action is triggered |
Styling and Theming
All components come with a clean, modern design that works without any CSS framework. The components use a consistent design system with CSS custom properties for easy theming.
Basic Styling
All component styles use the n-users-
prefix to avoid conflicts with your application styles:
/* Example: Customizing the user list grid */
.n-users-grid {
gap: 2rem; /* Increase spacing between user cards */
}
/* Example: Styling the delete button */
.n-users-delete-btn {
background-color: #dc2626;
border-radius: 6px;
}
Theme Support
The components automatically adapt to light and dark themes based on system preferences. You can also force a specific theme:
Force Light Theme
<template>
<div class="light">
<NUsersLoginForm />
</div>
</template>
Custom Theme Colors
<template>
<div class="custom-theme">
<NUsersLoginForm />
</div>
</template>
<style>
.custom-theme {
--nu-color-primary: #059669;
--nu-color-primary-dark: #047857;
--nu-color-bg-primary: #f0fdf4;
--nu-color-border: #059669;
}
</style>
Available CSS Custom Properties
Property | Description | Light Default | Dark Default |
---|---|---|---|
--nu-color-primary | Primary brand color | #3b82f6 | #60a5fa |
--nu-color-primary-dark | Darker primary variant | #2563eb | #3b82f6 |
--nu-color-bg-primary | Main background | #ffffff | #111827 |
--nu-color-bg-secondary | Secondary background | #f9fafb | #1f2937 |
--nu-color-border | Border color | #e5e7eb | #374151 |
Complete Styling Example
<template>
<div class="branded-auth">
<NUsersLoginForm
class="branded-login"
@success="handleSuccess"
>
<template #header>
<div class="brand-header">
<img src="/logo.png" alt="Company Logo" />
<h2>Welcome to MyApp</h2>
<p>Sign in to access your dashboard</p>
</div>
</template>
<template #submit-button>
<FormKit
type="submit"
class="brand-button"
>
Sign In to MyApp
</FormKit>
</template>
</NUsersLoginForm>
</div>
</template>
<style scoped>
.branded-auth {
--nu-color-primary: #7c3aed;
--nu-color-primary-dark: #6d28d9;
--nu-color-bg-primary: #faf5ff;
--nu-color-border: #c4b5fd;
}
.brand-header {
text-align: center;
margin-bottom: 2rem;
}
.brand-header img {
width: 80px;
height: 80px;
margin-bottom: 1rem;
}
.brand-header h2 {
color: #7c3aed;
font-size: 1.875rem;
font-weight: 700;
margin-bottom: 0.5rem;
}
.brand-button {
background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%) !important;
border: none !important;
font-weight: 600 !important;
text-transform: uppercase !important;
letter-spacing: 0.05em !important;
}
</style>
Troubleshooting
Build-Time Errors
If you encounter build-time errors like this:
[Vue Router warn]: uncaught error during route navigation:
ERROR [nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function.
This is a known issue that has been fixed in the module. The error occurs when components use composables that require Nuxt to be available during the build process.
Solution: Update to the latest version of the module. If you're still experiencing issues, please report it as a bug.
Note: This issue only affects certain components (NUsersList
, NUsersUserCard
, NUsersLogoutLink
, NUsersProfileInfo
) and has been resolved by implementing lazy initialization of composables.
Component Not Rendering
If a component is not rendering or appears empty:
- Check the console for any JavaScript errors
- Verify the component is properly imported and registered
- Ensure required props are provided (check the component documentation)
- Check that the API endpoints are accessible and returning data
Authentication Issues
If authentication components are not working:
- Verify your configuration - Check that
apiBasePath
is correctly set - Check network requests - Ensure API calls are reaching your server
- Review server logs - Look for any server-side errors
- Test with the playground - Try the components in the module's playground
Next Steps
- Getting Started - Learn how to set up authentication in your app
- Configuration - Explore configuration options for components
- Authentication - Understand the authentication system
- API Reference - Explore available API endpoints