Signup Form

A customizable form built on top of shadcn's input and label, with a touch of framer motion

Welcome to Aceternity

Login to aceternity if you can because we don't have a login flow yet

Installation

Install Dependencies

npm i svelte-motion clsx tailwind-merge @tabler/icons-svelte

Add util file

src/lib/utils/cn.ts
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
        
export function cn(...inputs: ClassValue[]) {
    return twMerge(clsx(inputs));
}

Modify the config file to add a plugin and a box shadow

tailwind.config.ts
import flattenColorPalette from 'tailwindcss/lib/util/flattenColorPalette';
// other imports...

const config = {
	// ... other properties
	theme: {
		extend: {
			boxShadow: {
				input: `0px 2px 3px -1px rgba(0,0,0,0.1), 0px 1px 0px 0px rgba(25,28,33,0.02), 0px 0px 0px 1px rgba(25,28,33,0.08)`
			}
		}
	},
	plugins: [addVariablesForColors]
};

function addVariablesForColors({ addBase, theme }: any) {
	let allColors = flattenColorPalette(theme('colors'));
	let newVars = Object.fromEntries(
		Object.entries(allColors).map(([key, val]) => [`--${key}`, val])
	);

	addBase({
		':root': newVars
	});
}

Copy the source code

src/lib/components/ui/SignupForm/Input.svelte
<script lang="ts">
	import { cn } from '@/utils';
	import { useMotionTemplate, useMotionValue, Motion, MotionValue } from 'svelte-motion';

	export let className: string | undefined = undefined;
	export let type: string = 'text';

	let visible = false;

	let mouseX = useMotionValue(0);
	let mouseY = useMotionValue(0);

	function handleMouseMove({ currentTarget, clientX, clientY }: any) {
		let { left, top } = currentTarget.getBoundingClientRect();

		mouseX.set(clientX - left);
		mouseY.set(clientY - top);
	}
</script>

<Motion
	let:motion
	style={{
		background: visible
			? useMotionTemplate`
  radial-gradient(
    100px circle at ${mouseX}px ${mouseY}px, 
    var(--blue-500),
    transparent 80%
  )
`
			: useMotionTemplate`
  radial-gradient(
    '0px' circle at ${mouseX}px ${mouseY}px,
    var(--blue-500),
    transparent 80%
  )
`
	}}
>
	<div
		use:motion
		on:mousemove={handleMouseMove}
		on:mouseenter={() => (visible = true)}
		on:mouseleave={() => (visible = false)}
		class="group/input rounded-lg p-[2px] transition duration-300"
	>
		<input
			{type}
			class={cn(
				`dark:placeholder-text-neutral-600 duration-400 flex h-10 w-full rounded-md border-none bg-gray-50 px-3 py-2 text-sm text-black shadow-input  transition file:border-0 
        file:bg-transparent file:text-sm file:font-medium placeholder:text-neutral-400 
        focus-visible:outline-none focus-visible:ring-[2px]  focus-visible:ring-neutral-400 disabled:cursor-not-allowed
         disabled:opacity-50 group-hover/input:shadow-none
         dark:bg-zinc-800
         dark:text-white dark:shadow-[0px_0px_1px_1px_var(--neutral-700)] dark:focus-visible:ring-neutral-600
         `,
				className
			)}
			{...$$restProps}
		/>
	</div>
</Motion>
src/lib/components/ui/SignupForm/Label.svelte
<script lang="ts">
	import { cn } from '@/utils';

	export let className: string | undefined = undefined;
</script>

<label
	class={cn(
		'text-sm font-medium leading-none text-black peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-white',
		className
	)}
	{...$$restProps}
>
	<slot />
</label>
src/lib/components/ui/SignupForm/index.ts
import Input from './Input.svelte';
import Label from './Label.svelte';

export { Input, Label };

Props

Input.svelte
Prop Type Description
className string | undefined Additional CSS classes to add to the Input Component
type string | undefined Specifies the type of input (e.g. "text", "password", "email". Inherits all standard HTML input types.
Label.svelte
Prop Type Description
className string | undefined Additional CSS classes to add to the Label Component