Tiesen Logo

Auth Components

Pre-built authentication components including user buttons, login forms, and other auth-related UI elements

Overview

This collection provides ready-to-use authentication components that you can integrate into your application. Each component is designed to handle common authentication patterns while being customizable to match your design system.

User Button

A user profile button component that displays the authenticated user's information and provides access to account actions.

'use client'

import { useTheme } from 'next-themes'

import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuPortal,
  DropdownMenuSeparator,
  DropdownMenuShortcut,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import {
  BellIcon,
  CreditCardIcon,
  LaptopIcon,
  LogOutIcon,
  MoonIcon,
  ShieldIcon,
  SunIcon,
  SunMoonIcon,
  UserIcon,
} from 'lucide-react'

export default function UserButton() {
  const { theme, setTheme } = useTheme()

  const user = {
    name: 'Tiesen',
    email: 'yuki@example.con',
    image: 'https://github.com/tiesen243.png',
  }

  return (
    <DropdownMenu>
      <DropdownMenuTrigger>
        <Avatar className='size-9 cursor-pointer'>
          <AvatarImage src={user.image} />
          <AvatarFallback>{user.name.slice(0, 2)}</AvatarFallback>
        </Avatar>
        <span className='sr-only'>Open user menu</span>
      </DropdownMenuTrigger>

      <DropdownMenuContent align='end' className='min-w-60'>
        <DropdownMenuLabel className='flex flex-col'>
          <p className='text-sm font-medium'>{user.name}</p>
          <p className='text-xs text-muted-foreground'>{user.email}</p>
        </DropdownMenuLabel>

        <DropdownMenuSeparator />

        <DropdownMenuGroup>
          {userNavItems.map((item) => (
            <DropdownMenuItem key={item.label} asChild>
              <a href={item.href}>
                <item.icon /> {item.label}
                <DropdownMenuShortcut>{item.shortcut}</DropdownMenuShortcut>
              </a>
            </DropdownMenuItem>
          ))}

          <DropdownMenuSub>
            <DropdownMenuSubTrigger className="gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground">
              <SunMoonIcon /> Apperance
            </DropdownMenuSubTrigger>
            <DropdownMenuPortal>
              <DropdownMenuSubContent>
                <DropdownMenuItem
                  className={
                    theme === 'light'
                      ? 'text-foreground'
                      : 'text-muted-foreground'
                  }
                  onClick={() => {
                    setTheme('light')
                  }}
                >
                  <SunIcon /> Light mode
                  <DropdownMenuShortcut>⌘L</DropdownMenuShortcut>
                </DropdownMenuItem>
                <DropdownMenuItem
                  className={
                    theme === 'dark'
                      ? 'text-foreground'
                      : 'text-muted-foreground'
                  }
                  onClick={() => {
                    setTheme('dark')
                  }}
                >
                  <MoonIcon /> Dark mode
                  <DropdownMenuShortcut>⌘D</DropdownMenuShortcut>
                </DropdownMenuItem>
                <DropdownMenuItem
                  className={
                    theme === 'system'
                      ? 'text-foreground'
                      : 'text-muted-foreground'
                  }
                  onClick={() => {
                    setTheme('system')
                  }}
                >
                  <LaptopIcon /> System
                  <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
                </DropdownMenuItem>
              </DropdownMenuSubContent>
            </DropdownMenuPortal>
          </DropdownMenuSub>
        </DropdownMenuGroup>

        <DropdownMenuSeparator />

        <DropdownMenuGroup>
          <DropdownMenuItem>
            <LogOutIcon /> Sign out
          </DropdownMenuItem>
        </DropdownMenuGroup>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

const userNavItems = [
  {
    href: '/account/profile',
    label: 'Profile',
    icon: UserIcon,
    shortcut: '⌘P',
  },
  {
    href: '/account/billing',
    label: 'Billing',
    icon: CreditCardIcon,
    shortcut: '⌘B',
  },
  {
    href: '/account/notifications',
    label: 'Notifications',
    icon: BellIcon,
    shortcut: '⌘N',
  },
  {
    href: '/account/security',
    label: 'Security',
    icon: ShieldIcon,
    shortcut: '⌘⇧S',
  },
]

Features

  • Display user avatar and name
  • Dropdown menu with account actions
  • Sign out functionality
  • Customizable styling

Login Form

A complete login form component with validation and error handling for user authentication.

'use client'

import { Button } from '@/components/ui/button'
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from '@/components/ui/card'
import { Input } from '@/components/ui/input'

import { useForm } from '@/components/ui/form'

export default function LoginForm() {
  const form = useForm({
    defaultValues: { email: '', password: '' },
    validator: (value) => {
      const issues: { path: string[]; message: string }[] = []
      if (value.email.trim() === '')
        issues.push({ path: ['email'], message: 'Email is required' })
      if (value.password.trim() === '')
        issues.push({ path: ['password'], message: 'Password is required' })
      if (issues.length > 0) return { issues }
      return { value }
    },
    onSubmit: console.log,
  })

  return (
    <Card className='min-w-md'>
      <CardHeader>
        <CardTitle>Login to your account</CardTitle>
        <CardDescription>
          Please enter your email and password to log in.
        </CardDescription>
      </CardHeader>

      <CardContent>
        <form
          className='grid gap-4'
          onSubmit={(e) => {
            e.preventDefault()
            e.stopPropagation()
            form.handleSubmit()
          }}
        >
          <form.Field
            name='email'
            render={({ field, meta }) => (
              <div id={meta.id} className='grid gap-2'>
                <form.Label>Email</form.Label>
                <form.Control {...field}>
                  <Input type='email' placeholder='Enter your email' />
                </form.Control>
                <form.Message />
              </div>
            )}
          />

          <form.Field
            name='password'
            render={({ field, meta }) => (
              <div id={meta.id} className='grid gap-2'>
                <div className='flex items-center justify-between'>
                  <form.Label>Password</form.Label>
                  <a href='#' className='text-xs hover:underline'>
                    Forgot your password?
                  </a>
                </div>
                <form.Control {...field}>
                  <Input type='password' placeholder='Enter your password' />
                </form.Control>
                <form.Message />
              </div>
            )}
          />

          <Button disabled={form.state.isPending}>Login</Button>
        </form>
      </CardContent>
    </Card>
  )
}

Features

  • Email and password inputs
  • Form validation
  • Error handling and display
  • Loading states
  • Forgot password link

Customization

All components accept standard React props and can be styled using CSS classes or styled-components. Refer to the individual component code for available props and customization options.