Sign-Up Form
A comprehensive registration pattern featuring multiple input types, validation simulation, and terms acceptance.
Demo
Implementation
vue
<script setup lang="ts">
import { ref } from 'vue';
// 1. Component Imports (Default)
import CLCard from '@codeandfunction/callaloo/CLCard';
import CLInput from '@codeandfunction/callaloo/CLInput';
import CLButton from '@codeandfunction/callaloo/CLButton';
import CLHeading from '@codeandfunction/callaloo/CLHeading';
import CLText from '@codeandfunction/callaloo/CLText';
import CLLink from '@codeandfunction/callaloo/CLLink';
import CLCheckbox from '@codeandfunction/callaloo/CLCheckbox';
import { useToast } from '@codeandfunction/callaloo/composables/useToast';
// 2. Enum & Type Imports (Named)
import {
CLIconNames,
CLColors,
CLInputTypes,
CLTextTypes,
CLHeadingLevels,
CLHeadingTypes,
CLButtonTypes,
CLColorVariants
} from '@codeandfunction/callaloo';
// 3. State & Logic
const name = ref('');
const email = ref('');
const password = ref('');
const confirmPassword = ref('');
const acceptTerms = ref(false);
const isLoading = ref(false);
const toast = useToast();
const handleRegister = async (): Promise<void> => {
if (password.value !== confirmPassword.value) {
toast.showToast({
color: CLColors.Danger,
message: 'Passwords do not match!',
title: 'Error',
});
return;
}
isLoading.value = true;
await new Promise(resolve => setTimeout(resolve, 1500));
isLoading.value = false;
toast.showToast({
color: CLColors.Success,
message: 'Registration simulated!',
title: 'Success',
});
};
</script>
<template>
<div class="pattern-preview">
<CLCard :variant="CLColorVariants.Outline" elevated>
<template #heading>
<div class="header-content">
<CLHeading :level="CLHeadingLevels.H2" :type="CLHeadingTypes.Large">Create Account</CLHeading>
<CLText :color="CLColors.Neutral" :type="CLTextTypes.Small">Join our community today</CLText>
</div>
</template>
<form @submit.prevent="handleRegister" class="form-content">
<CLInput
id="name"
name="name"
label="Full Name"
v-model="name"
:prefix="CLIconNames.User"
fluid
required
/>
<CLInput
id="email"
name="email"
label="Email"
v-model="email"
:prefix="CLIconNames.Mail"
:type="CLInputTypes.Email"
fluid
required
/>
<CLInput
id="password"
name="password"
label="Password"
v-model="password"
:prefix="CLIconNames.Lock"
:type="CLInputTypes.Password"
fluid
required
/>
<CLInput
id="confirm-password"
name="confirm-password"
label="Confirm Password"
v-model="confirmPassword"
:prefix="CLIconNames.Lock"
:type="CLInputTypes.Password"
fluid
required
/>
<div class="terms-check">
<CLCheckbox
v-model="acceptTerms"
id="terms"
name="terms"
required
/>
<label for="terms" class="terms-label">
<CLText :type="CLTextTypes.Small" as="span">
I accept the <CLLink href="#">Terms of Service</CLLink>
</CLText>
</label>
</div>
<CLButton
:type="CLButtonTypes.Submit"
:color="CLColors.Primary"
:busy="isLoading"
:disabled="isLoading || !acceptTerms"
width="100%"
>
Create Account
</CLButton>
</form>
<template #footer>
<div class="footer-content">
<CLText :type="CLTextTypes.Small">
Already have an account? <CLLink href="./login-form">Sign In</CLLink>
</CLText>
</div>
</template>
</CLCard>
</div>
</template>
<style scoped>
.pattern-preview {
display: flex;
justify-content: center;
align-items: center;
flex: 1;
margin: 0 auto;
height: 100%;
}
.header-content {
text-align: center;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.form-content {
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 1rem 0;
}
.terms-check {
display: flex;
align-items: center;
gap: 0.5rem;
}
.terms-label {
display: inline-flex;
align-items: center;
cursor: pointer;
}
.footer-content {
display: flex;
justify-content: center;
}
</style>