Usage
Built on top of the Form component, the AuthForm component can be used in your pages or wrapped in a PageCard.
<script setup lang="ts">
import type { AuthFormField, FormSubmitEvent } from 'pohon-ui';
import * as z from 'zod';
const toast = useToast();
const fields: Array<AuthFormField> = [{
name: 'email',
type: 'email',
label: 'Email',
placeholder: 'Enter your email',
required: true,
}, {
name: 'password',
label: 'Password',
type: 'password',
placeholder: 'Enter your password',
required: true,
}, {
name: 'remember',
label: 'Remember me',
type: 'checkbox',
}];
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.email('Invalid email'),
password: z.string('Password is required').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="p-4 flex flex-col gap-4 items-center justify-center">
<PPageCard class="max-w-md w-full">
<PAuthForm
:schema="schema"
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:fields="fields"
:providers="providers"
@submit="onSubmit"
/>
</PPageCard>
</div>
</template>
Fields
The Form will construct itself based on the fields prop and the state will be handled internally.
Use the fields prop as an array of objects with the following properties:
name: stringtype: 'checkbox' | 'select' | 'otp' | 'InputHTMLAttributes['type']'
Each field must include a type property, which determines the input component and any additional props applied: checkbox fields use Checkbox props, select fields use SelectMenu props, otp fields use PinInput props, and all other types use Input props.
You can also pass any property from the FormField component to each field.
<script setup lang="ts">
import type { AuthFormField } from 'pohon-ui'
const fields = ref<AuthFormField[]>([
{
name: 'email',
type: 'email',
label: 'Email',
placeholder: 'Enter your email',
required: true
},
{
name: 'password',
type: 'password',
label: 'Password',
placeholder: 'Enter your password',
required: true
},
{
name: 'country',
type: 'select',
label: 'Country',
placeholder: 'Select country',
items: [
{
label: 'United States',
value: 'us'
},
{
label: 'France',
value: 'fr'
},
{
label: 'United Kingdom',
value: 'uk'
},
{
label: 'Australia',
value: 'au'
}
]
},
{
name: 'otp',
type: 'otp',
label: 'OTP',
length: 6,
placeholder: '○'
},
{
name: 'remember',
type: 'checkbox',
label: 'Remember me',
description: 'You will be logged in for 30 days.'
}
])
</script>
<template>
<PAuthForm :fields="fields" class="max-w-sm" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { AuthFormField } from 'pohon-ui'
const fields = ref<AuthFormField[]>([
{
name: 'email',
type: 'email',
label: 'Email',
placeholder: 'Enter your email',
required: true
},
{
name: 'password',
type: 'password',
label: 'Password',
placeholder: 'Enter your password',
required: true
},
{
name: 'country',
type: 'select',
label: 'Country',
placeholder: 'Select country',
items: [
{
label: 'United States',
value: 'us'
},
{
label: 'France',
value: 'fr'
},
{
label: 'United Kingdom',
value: 'uk'
},
{
label: 'Australia',
value: 'au'
}
]
},
{
name: 'otp',
type: 'otp',
label: 'OTP',
length: 6,
placeholder: '○'
},
{
name: 'remember',
type: 'checkbox',
label: 'Remember me',
description: 'You will be logged in for 30 days.'
}
])
</script>
<template>
<PAuthForm :fields="fields" class="max-w-sm" />
</template>Title
Use the title prop to set the title of the Form.
<script setup lang="ts">
import type { AuthFormField } from 'pohon-ui'
const fields = ref<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm title="Login" :fields="fields" class="max-w-md" />
</template><script setup lang="ts">
import { ref } from 'vue'
import type { AuthFormField } from 'pohon-ui'
const fields = ref<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm title="Login" :fields="fields" class="max-w-md" />
</template>div by default. Use the as prop with an object to render it as a heading, for example :as="{ title: 'h3' }". You can also set the root element this way: :as="{ root: 'section', title: 'h3' }".Description
Use the description prop to set the description of the Form.
<script setup lang="ts">
import type { AuthFormField } from 'pohon-ui'
const fields = ref<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
:fields="fields"
class="max-w-md"
/>
</template><script setup lang="ts">
import { ref } from 'vue'
import type { AuthFormField } from 'pohon-ui'
const fields = ref<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
:fields="fields"
class="max-w-md"
/>
</template>Icon
Use the icon prop to set the icon of the Form.
<script setup lang="ts">
import type { AuthFormField } from 'pohon-ui'
const fields = ref<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:fields="fields"
class="max-w-md"
/>
</template><script setup lang="ts">
import { ref } from 'vue'
import type { AuthFormField } from 'pohon-ui'
const fields = ref<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:fields="fields"
class="max-w-md"
/>
</template>Providers
Use the providers prop to add providers to the form.
You can pass any property from the Button component such as variant, color, to, etc.
<script setup lang="ts">
import type { ButtonProps, AuthFormField } from 'pohon-ui'
const providers = ref<ButtonProps[]>([
{
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<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:providers="providers"
:fields="fields"
class="max-w-md"
/>
</template><script setup lang="ts">
import { ref } from 'vue'
import type { ButtonProps, AuthFormField } from 'pohon-ui'
const providers = ref<ButtonProps[]>([
{
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<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:providers="providers"
:fields="fields"
class="max-w-md"
/>
</template>Separator
Use the separator prop to customize the Separator between the providers and the fields. Defaults to or.
<script setup lang="ts">
import type { ButtonProps, AuthFormField } from 'pohon-ui'
const providers = ref<ButtonProps[]>([
{
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<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:providers="providers"
:fields="fields"
separator="Providers"
class="max-w-md"
/>
</template><script setup lang="ts">
import { ref } from 'vue'
import type { ButtonProps, AuthFormField } from 'pohon-ui'
const providers = ref<ButtonProps[]>([
{
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<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:providers="providers"
:fields="fields"
separator="Providers"
class="max-w-md"
/>
</template>You can pass any property from the Separator component to customize it.
<script setup lang="ts">
import type { ButtonProps, AuthFormField } from 'pohon-ui'
const providers = ref<ButtonProps[]>([
{
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<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:providers="providers"
:fields="fields"
:separator="{
icon: 'i-lucide-user'
}"
class="max-w-md"
/>
</template><script setup lang="ts">
import { ref } from 'vue'
import type { ButtonProps, AuthFormField } from 'pohon-ui'
const providers = ref<ButtonProps[]>([
{
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<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:providers="providers"
:fields="fields"
:separator="{
icon: 'i-lucide-user'
}"
class="max-w-md"
/>
</template>Submit
Use the submit prop to change the submit button of the Form.
You can pass any property from the Button component such as variant, color, to, etc.
<script setup lang="ts">
import type { AuthFormField } from 'pohon-ui'
const fields = ref<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:fields="fields"
:submit="{
label: 'Submit',
color: 'error',
variant: 'subtle'
}"
class="max-w-md"
/>
</template><script setup lang="ts">
import { ref } from 'vue'
import type { AuthFormField } from 'pohon-ui'
const fields = ref<AuthFormField[]>([
{
name: 'email',
type: 'text',
label: 'Email'
},
{
name: 'password',
type: 'password',
label: 'Password'
}
])
</script>
<template>
<PAuthForm
title="Login"
description="Enter your credentials to access your account."
icon="i-lucide-user"
:fields="fields"
:submit="{
label: 'Submit',
color: 'error',
variant: 'subtle'
}"
class="max-w-md"
/>
</template>Examples
Within a page
You can wrap the AuthForm component with the PageCard component to display it within a login.vue page for example.
<script setup lang="ts">
import type { AuthFormField, FormSubmitEvent } from 'pohon-ui';
import * as z from 'zod';
const toast = useToast();
const fields: Array<AuthFormField> = [{
name: 'email',
type: 'email',
label: 'Email',
placeholder: 'Enter your email',
required: true,
}, {
name: 'password',
label: 'Password',
type: 'password',
placeholder: 'Enter your password',
required: true,
}, {
name: 'remember',
label: 'Remember me',
type: 'checkbox',
}];
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.email('Invalid email'),
password: z.string('Password is required').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="p-4 flex flex-col gap-4 items-center justify-center">
<PPageCard class="max-w-md w-full">
<PAuthForm
:schema="schema"
:fields="fields"
:providers="providers"
title="Welcome back!"
icon="i-lucide-lock"
@submit="onSubmit"
>
<template #description>
Don't have an account? <PLink
to="#"
class="color-primary font-medium"
>
Sign up
</PLink>.
</template>
<template #password-hint>
<PLink
to="#"
class="color-primary font-medium"
tabindex="-1"
>
Forgot password?
</PLink>
</template>
<template #validation>
<PAlert
color="error"
icon="i-lucide-info"
title="Error signing in"
/>
</template>
<template #footer>
By signing in, you agree to our <PLink
to="#"
class="color-primary font-medium"
>
Terms of Service
</PLink>.
</template>
</PAuthForm>
</PPageCard>
</div>
</template>
API
Props
| Prop | Default | Type |
|---|
Slots
| Slot | Type |
|---|
Emits
| Event | Type |
|---|
Expose
You can access the typed component instance (exposing formRef and state) using useTemplateRef. For example, in a separate form (e.g. a "reset" form) you can do:
<script setup lang="ts">
const authForm = useTemplateRef('authForm');
</script>
<template>
<PAuthForm ref="authForm" />
</template>
This gives you access to the following (exposed) properties:
| Name | Type |
|---|---|
formRef | Ref<HTMLFormElement | null> |
state | Reactive<FormStateType> |
Theme
export default defineAppConfig({
ui: {
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-600 color-text-highlighted',
description: 'mt-1 text-base text-pretty color-text-muted',
body: 'gap-y-6 flex flex-col',
providers: 'space-y-3',
checkbox: '',
select: 'w-full',
password: 'w-full',
otp: 'w-full',
input: 'w-full',
separator: '',
form: 'space-y-5',
footer: 'text-sm text-center color-text-muted mt-2'
}
}
}
})import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from 'pohon-ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
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-600 color-text-highlighted',
description: 'mt-1 text-base text-pretty color-text-muted',
body: 'gap-y-6 flex flex-col',
providers: 'space-y-3',
checkbox: '',
select: 'w-full',
password: 'w-full',
otp: 'w-full',
input: 'w-full',
separator: '',
form: 'space-y-5',
footer: 'text-sm text-center color-text-muted mt-2'
}
}
}
})
]
})