Login Form
A common authentication pattern combining a card layout, input fields, and validation states.
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 { useToast } from '@codeandfunction/callaloo/composables/useToast';
// 2. Enum & Type Imports (Named)
import {
CLIconNames,
CLColors,
CLInputTypes,
CLTextTypes,
CLHeadingLevels,
CLHeadingTypes,
CLColorVariants
} from '@codeandfunction/callaloo';
// 3. State & Logic
const email = ref('');
const password = ref('');
const isLoading = ref(false);
const toast = useToast();
const handleLogin = async (): Promise<void> => {
isLoading.value = true;
await new Promise(resolve => setTimeout(resolve, 1500));
isLoading.value = false;
toast.showToast({
color: CLColors.Success,
message: 'Login 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">Welcome Back</CLHeading>
<CLText :color="CLColors.Neutral" :type="CLTextTypes.Small">Please sign in to your account</CLText>
</div>
</template>
<form @submit.prevent="handleLogin" class="form-content">
<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
/>
<CLButton
type="submit"
:color="CLColors.Primary"
:busy="isLoading"
:disabled="isLoading"
width="100%"
>
Sign In
</CLButton>
</form>
<template #footer>
<div class="footer-content">
<CLText :type="CLTextTypes.Small">
<CLLink href="#">Forgot Password?</CLLink>
</CLText>
</div>
</template>
</CLCard>
</div>
</template>
<style scoped>
.pattern-preview {
display: flex;
justify-content: center;
align-items: center;
flex: 1;
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;
}
.footer-content {
display: flex;
justify-content: center;
}
</style>