AuthFormPRO

FormGitHub
一个可自定义的表单,用于创建登录、注册或密码重置表单。

用法

`AuthForm` 组件构建于 Form 组件之上,可用于您的页面或封装在 PageCard 中。

表单将根据 `fields` 属性自行构建,状态将在内部处理。您可以将传递给 FormFieldInput 的所有属性传递给每个字段。

<script setup lang="ts">
import * as z from 'zod'
import type { FormSubmitEvent } from '@nuxt/ui'

const toast = useToast()

const fields = [{
  name: 'email',
  type: 'text' as const,
  label: 'Email',
  placeholder: 'Enter your email',
  required: true
}, {
  name: 'password',
  label: 'Password',
  type: 'password' as const,
  placeholder: 'Enter your password'
}, {
  name: 'remember',
  label: 'Remember me',
  type: 'checkbox' as const
}]

const providers = [{
  label: 'Google',
  icon: 'i-simple-icons-google',
  onClick: () => {
    toast.add({ title: 'Google', description: 'Login with Google' })
  }
}, {
  label: 'GitHub',
  icon: 'i-simple-icons-github',
  onClick: () => {
    toast.add({ title: 'GitHub', description: 'Login with GitHub' })
  }
}]

const schema = z.object({
  email: z.string().email('Invalid email'),
  password: z.string().min(8, 'Must be at least 8 characters')
})

type Schema = z.output<typeof schema>

function onSubmit(payload: FormSubmitEvent<Schema>) {
  console.log('Submitted', payload)
}
</script>

<template>
  <div class="flex flex-col items-center justify-center gap-4 p-4">
    <UPageCard class="w-full max-w-md">
      <UAuthForm
        :schema="schema"
        title="Login"
        description="Enter your credentials to access your account."
        icon="i-lucide-user"
        :fields="fields"
        :providers="providers"
        @submit="onSubmit"
      />
    </UPageCard>
  </div>
</template>

标题

使用 `title` 属性设置表单的标题。

登录
<script setup lang="ts">
const fields = ref([
  {
    name: 'email',
    type: 'text',
    label: 'Email'
  },
  {
    name: 'password',
    type: 'password',
    label: 'Password'
  }
])
</script>

<template>
  <UAuthForm class="max-w-md" title="Login" :fields="fields" />
</template>

描述

使用 `description` 属性设置表单的描述。

登录
输入您的凭据以访问您的账户。
<script setup lang="ts">
const fields = ref([
  {
    name: 'email',
    type: 'text',
    label: 'Email'
  },
  {
    name: 'password',
    type: 'password',
    label: 'Password'
  }
])
</script>

<template>
  <UAuthForm
    class="max-w-md"
    title="Login"
    description="Enter your credentials to access your account."
    :fields="fields"
  />
</template>

Icon

使用 `icon` 属性设置表单的图标。

登录
输入您的凭据以访问您的账户。
<script setup lang="ts">
const fields = ref([
  {
    name: 'email',
    type: 'text',
    label: 'Email'
  },
  {
    name: 'password',
    type: 'password',
    label: 'Password'
  }
])
</script>

<template>
  <UAuthForm
    class="max-w-md"
    title="Login"
    description="Enter your credentials to access your account."
    icon="i-lucide-user"
    :fields="fields"
  />
</template>

提供商

使用 `providers` 属性为表单添加提供商。

您可以传递 Button 组件的任何属性,例如 `variant`、`color`、`to` 等。

登录
输入您的凭据以访问您的账户。
<script setup lang="ts">
const fields = ref([
  {
    name: 'email',
    type: 'text',
    label: 'Email'
  },
  {
    name: 'password',
    type: 'password',
    label: 'Password'
  }
])
const providers = ref([
  {
    label: 'Google',
    icon: 'i-simple-icons-google',
    color: 'neutral',
    variant: 'subtle'
  },
  {
    label: 'GitHub',
    icon: 'i-simple-icons-github',
    color: 'neutral',
    variant: 'subtle'
  }
])
</script>

<template>
  <UAuthForm
    class="max-w-md"
    title="Login"
    description="Enter your credentials to access your account."
    icon="i-lucide-user"
    :providers="providers"
    :fields="fields"
  />
</template>

Separator

使用 `separator` 属性自定义提供商和字段之间的 Separator。默认为 `or`。

登录
输入您的凭据以访问您的账户。
<script setup lang="ts">
const providers = ref([
  {
    label: 'Google',
    icon: 'i-simple-icons-google',
    color: 'neutral',
    variant: 'subtle'
  },
  {
    label: 'GitHub',
    icon: 'i-simple-icons-github',
    color: 'neutral',
    variant: 'subtle'
  }
])
const fields = ref([
  {
    name: 'email',
    type: 'text',
    label: 'Email'
  },
  {
    name: 'password',
    type: 'password',
    label: 'Password'
  }
])
</script>

<template>
  <UAuthForm
    class="max-w-md"
    title="Login"
    description="Enter your credentials to access your account."
    icon="i-lucide-user"
    :providers="providers"
    :fields="fields"
    separator="Providers"
  />
</template>

您可以传递 Separator 组件的任何属性来自定义它。

登录
输入您的凭据以访问您的账户。
<script setup lang="ts">
const providers = ref([
  {
    label: 'Google',
    icon: 'i-simple-icons-google',
    color: 'neutral',
    variant: 'subtle'
  },
  {
    label: 'GitHub',
    icon: 'i-simple-icons-github',
    color: 'neutral',
    variant: 'subtle'
  }
])
const fields = ref([
  {
    name: 'email',
    type: 'text',
    label: 'Email'
  },
  {
    name: 'password',
    type: 'password',
    label: 'Password'
  }
])
</script>

<template>
  <UAuthForm
    class="max-w-md"
    title="Login"
    description="Enter your credentials to access your account."
    icon="i-lucide-user"
    :providers="providers"
    :fields="fields"
    :separator="{
      icon: 'i-lucide-user'
    }"
  />
</template>

提交

使用 `submit` 属性更改表单的提交按钮。

您可以传递 Button 组件的任何属性,例如 `variant`、`color`、`to` 等。

登录
输入您的凭据以访问您的账户。
<script setup lang="ts">
const fields = ref([
  {
    name: 'email',
    type: 'text',
    label: 'Email'
  },
  {
    name: 'password',
    type: 'password',
    label: 'Password'
  }
])
</script>

<template>
  <UAuthForm
    class="max-w-md"
    title="Login"
    description="Enter your credentials to access your account."
    icon="i-lucide-user"
    :fields="fields"
    :submit="{
      label: 'Submit',
      color: 'error',
      variant: 'subtle'
    }"
  />
</template>

示例

在页面内

您可以将 `AuthForm` 组件与 PageCard 组件一起封装,例如在 `login.vue` 页面中显示它。

<script setup lang="ts">
import * as z from 'zod'
import type { FormSubmitEvent } from '@nuxt/ui'

const toast = useToast()

const fields = [{
  name: 'email',
  type: 'text' as const,
  label: 'Email',
  placeholder: 'Enter your email',
  required: true
}, {
  name: 'password',
  label: 'Password',
  type: 'password' as const,
  placeholder: 'Enter your password'
}, {
  name: 'remember',
  label: 'Remember me',
  type: 'checkbox' as const
}]

const providers = [{
  label: 'Google',
  icon: 'i-simple-icons-google',
  onClick: () => {
    toast.add({ title: 'Google', description: 'Login with Google' })
  }
}, {
  label: 'GitHub',
  icon: 'i-simple-icons-github',
  onClick: () => {
    toast.add({ title: 'GitHub', description: 'Login with GitHub' })
  }
}]

const schema = z.object({
  email: z.string().email('Invalid email'),
  password: z.string().min(8, 'Must be at least 8 characters')
})

type Schema = z.output<typeof schema>

function onSubmit(payload: FormSubmitEvent<Schema>) {
  console.log('Submitted', payload)
}
</script>

<template>
  <div class="flex flex-col items-center justify-center gap-4 p-4">
    <UPageCard class="w-full max-w-md">
      <UAuthForm
        :schema="schema"
        :fields="fields"
        :providers="providers"
        title="Welcome back!"
        icon="i-lucide-lock"
        @submit="onSubmit"
      >
        <template #description>
          Don't have an account? <ULink to="#" class="text-primary font-medium">Sign up</ULink>.
        </template>
        <template #password-hint>
          <ULink to="#" class="text-primary font-medium" tabindex="-1">Forgot password?</ULink>
        </template>
        <template #validation>
          <UAlert color="error" icon="i-lucide-info" title="Error signing in" />
        </template>
        <template #footer>
          By signing in, you agree to our <ULink to="#" class="text-primary font-medium">Terms of Service</ULink>.
        </template>
      </UAuthForm>
    </UPageCard>
  </div>
</template>

OTP / 2FA 示例

您可以通过在 `fields` 数组中使用 `otp` 类型来添加一次性密码 (OTP) 字段以进行双因素身份验证。`otp` 属性允许您传递 PinInput 组件支持的任何属性。

使用 2FA 登录
<script setup lang="ts">
const fields = ref([
  {
    name: 'email',
    type: 'text',
    label: 'Email'
  },
  {
    name: 'password',
    type: 'password',
    label: 'Password'
  },
  {
    name: 'otp',
    type: 'otp',
    otp: {
      length: 6,
      placeholder: ''
    }
  }
])
</script>

<template>
  <UAuthForm class="max-w-md" title="Login with 2FA" :fields="fields" />
</template>

API

属性

属性默认值类型
as

'div'

任何

此组件应渲染为的元素或组件。

图标

字符串

显示在标题上方的图标。

标题

字符串

描述

字符串

fields

AuthFormField[]

providers

ButtonProps[]

在描述下方显示一个 Button 列表。{ color: 'neutral', variant: 'subtle', block: true }

分隔符

'or'

string | SeparatorProps

分隔符中显示的文本。

submit

ButtonProps

在表单底部显示一个提交按钮。{ label: 'Continue', block: true }

schema

Struct<any, any> | ObjectSchema<object, AnyObject, any, ""> | AnySchema<object> | ArraySchema<object> | AlternativesSchema<object> | BinarySchema<object> | BooleanSchema<object> | DateSchema<object> | FunctionSchema<object> | NumberSchema<object> | ObjectSchema<object> | StringSchema<object> | LinkSchema<object> | SymbolSchema<object> | StandardSchemaV1<object, object>

validate

(state: Partial<any>): FormError<string>[] | Promise<FormError<string>[]>

validateOn

FormInputEvents[]

validateOnInputDelay

数字

disabled

布尔值

loading

布尔值

loadingAuto

布尔值

ui

{ root?: ClassNameValue; header?: ClassNameValue; leading?: ClassNameValue; leadingIcon?: ClassNameValue; title?: ClassNameValue; description?: ClassNameValue; body?: ClassNameValue; providers?: ClassNameValue; checkbox?: ClassNameValue; select?: ClassNameValue; password?: ClassNameValue; otp?: ClassNameValue; input?: ClassNameValue; separator?: ClassNameValue; form?: ClassNameValue; footer?: ClassNameValue; }

插槽

插槽类型
页头

{}

前置

{}

标题

{}

描述

{}

providers

{}

validation

{}

submit

{ loading: boolean; }

页脚

{}

事件

事件类型
submit

[FormSubmitEvent<any>]

可访问属性

您可以使用useTemplateRef来访问类型化的组件实例(暴露 formRef 和 state)。例如,在单独的表单中(例如“reset”表单),您可以这样做

<script setup lang="ts">
const authForm = useTemplateRef('authForm')
</script>

<template>
  <UAuthForm ref="authForm" />
</template>

这使您可以访问以下(暴露的)属性

名称类型
formRefRef<HTMLFormElement | null>
stateReactive<FormStateType>

主题

app.config.ts
export default defineAppConfig({
  uiPro: {
    authForm: {
      slots: {
        root: 'w-full space-y-6',
        header: 'flex flex-col text-center',
        leading: 'mb-2',
        leadingIcon: 'size-8 shrink-0 inline-block',
        title: 'text-xl text-pretty font-semibold text-highlighted',
        description: 'mt-1 text-base text-pretty text-muted',
        body: 'gap-y-6 flex flex-col',
        providers: 'space-y-3',
        checkbox: '',
        select: '',
        password: 'w-full',
        otp: 'w-full justify-center',
        input: 'w-full',
        separator: '',
        form: 'space-y-5',
        footer: 'text-sm text-center text-muted mt-2'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      uiPro: {
        authForm: {
          slots: {
            root: 'w-full space-y-6',
            header: 'flex flex-col text-center',
            leading: 'mb-2',
            leadingIcon: 'size-8 shrink-0 inline-block',
            title: 'text-xl text-pretty font-semibold text-highlighted',
            description: 'mt-1 text-base text-pretty text-muted',
            body: 'gap-y-6 flex flex-col',
            providers: 'space-y-3',
            checkbox: '',
            select: '',
            password: 'w-full',
            otp: 'w-full justify-center',
            input: 'w-full',
            separator: '',
            form: 'space-y-5',
            footer: 'text-sm text-center text-muted mt-2'
          }
        }
      }
    })
  ]
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      uiPro: {
        authForm: {
          slots: {
            root: 'w-full space-y-6',
            header: 'flex flex-col text-center',
            leading: 'mb-2',
            leadingIcon: 'size-8 shrink-0 inline-block',
            title: 'text-xl text-pretty font-semibold text-highlighted',
            description: 'mt-1 text-base text-pretty text-muted',
            body: 'gap-y-6 flex flex-col',
            providers: 'space-y-3',
            checkbox: '',
            select: '',
            password: 'w-full',
            otp: 'w-full justify-center',
            input: 'w-full',
            separator: '',
            form: 'space-y-5',
            footer: 'text-sm text-center text-muted mt-2'
          }
        }
      }
    })
  ]
})