The settings page demonstrates how to use @nuxt/ui components (UForm, UFormField, UInput, etc.) in conjunction with zod for schema-based form validation.
Key implementation steps:
- Define a Schema: Use
z.object() to define the shape and validation rules (e.g., .min(), .email()) for your form data. - Define State: Create a reactive object (using
reactive) that matches the schema's output type. Use Partial<T> if you want to allow empty initial states. - Bind to UForm: Pass the
schema and the state object to the <UForm> component. Use the @submit event to handle the validated data. - Handle File Uploads: For avatar/image uploads, use a hidden
<input type="file"> and trigger its click event via a ref when a UI button is clicked. Use URL.createObjectURL() to generate a preview URL for the UAvatar component.
<script setup lang="ts">
import * as z from 'zod'
import type { FormSubmitEvent } from '@nuxt/ui'
// 1. Define validation schema
const profileSchema = z.object({
name: z.string().min(2, 'Too short'),
email: z.string().email('Invalid email'),
username: z.string().min(2, 'Too short'),
avatar: z.string().optional(),
bio: z.string().optional()
})
type ProfileSchema = z.output<typeof profileSchema>
// 2. Define reactive state
const profile = reactive<Partial<ProfileSchema>>({
name: 'Benjamin Canac',
email: 'ben@nuxtlabs.com',
username: 'benjamincanac'
})
// 3. Handle submission
async function onSubmit(event: FormSubmitEvent<ProfileSchema>) {
console.log(event.data)
}
</script>
<template>
<UForm
:schema="profileSchema"
:state="profile"
@submit="onSubmit"
>
<!-- Form fields go here -->
<UFormField name="name" label="Name">
<UInput v-model="profile.name" />
</UFormField>
<UButton type="submit">Save changes</UButton>
</UForm>
</template>