Form â
Credit card â
Payment Details
TIP
We are not using .a-card-spacer
class here because we get spacing between card body via Anu's grid system đ
vue
<script lang="ts" setup>
import { reactive } from 'vue'
const creditCardDetails = reactive({
cardHolderName: '',
creditCardNum: undefined,
expiration: '',
cvc: undefined,
})
</script>
<template>
<ACard title="Payment Details">
<div class="grid-row place-items-stretch sm:grid-cols-2 a-card-body">
<AInput
v-model.trim="creditCardDetails.cardHolderName"
label="Card Holder"
placeholder="John Doe"
class="sm:col-span-2"
/>
<AInput
v-model.number="creditCardDetails.creditCardNum"
label="Card Number"
placeholder="4444 3333 2222 1111"
class="sm:col-span-2"
type="number"
/>
<AInput
v-model.trim="creditCardDetails.expiration"
label="Expiration"
placeholder="23/12"
/>
<AInput
v-model.trim.number="creditCardDetails.cvc"
label="CVV"
placeholder="987"
type="number"
/>
<!-- Action button -->
<ABtn class="justify-self-start">
Submit
</ABtn>
</div>
</ACard>
</template>
Form Validation using Zod â
vue
<script lang="ts" setup>
import { toFormValidator } from '@vee-validate/zod'
import { useField, useForm } from 'vee-validate'
import * as zod from 'zod'
const validationSchema = toFormValidator(
zod.object({
email: zod.string({ required_error: 'Email is required' }).min(1).email({ message: 'Must be a valid email' }),
password: zod.string({ required_error: 'Password is required' }).min(1).min(8, { message: 'Password is too short' }),
}),
)
const { handleSubmit, errors } = useForm({
validationSchema,
})
/*
setting `validateOnValueUpdate: false` won't trigger validation on value change
Docs: https://vee-validate.logaretm.com/v4/guide/composition-api/validation/#validation-behavior
*/
const { value: email } = useField<string>('email', undefined, {
validateOnValueUpdate: false,
})
const { value: password } = useField<string>('password', undefined, {
validateOnValueUpdate: false,
})
const onSubmit = handleSubmit((values, { resetForm }) => {
alert(JSON.stringify(values, null, 2))
resetForm()
})
</script>
<template>
<ACard>
<div class="a-card-body py-18">
<form
class="grid-row mx-auto max-w-1/2 grid-flow-rows justify-items-stretch content-center"
@submit="onSubmit"
>
<ATypography
:title="['Hello Again!', 'text-2xl']"
subtitle="Welcome back, You've been missed"
class="mb-4"
/>
<AInput
v-model="email"
name="email"
type="email"
label="Email"
:error="errors.email"
/>
<AInput
v-model="password"
name="password"
type="password"
label="Password"
:error="errors.password"
/>
<ABtn>Submit</ABtn>
</form>
</div>
</ACard>
</template>
Copy Secrets â
vue
<script lang="ts" setup>
import { useClipboard } from '@vueuse/core'
import { ref } from 'vue'
// Fetch secret from API
const mySecret = ref('7PDyLiPNRu58nhJe2DxK')
const { copy, copied } = useClipboard({ source: mySecret })
</script>
<template>
<!-- âšī¸ Secret shouldn't be directly editable. Hence, we aren't using v-model. -->
<AInput
type="password"
readonly
:model-value="mySecret"
>
<template #append-inner>
<div
class="flex items-center gap-x-2 pointer-events-auto"
:class="copied ? '' : 'cursor-pointer'"
@click.stop="copy(mySecret)"
>
<i :class="copied ? 'i-bx-check' : 'i-bx-clipboard'" />
</div>
</template>
</AInput>
</template>