Skip to main content

Split Login page using tailwind css & shadcn

Updated 3 min readMarkdown
import { useState } from "react"
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
import { Link, useNavigate } from "react-router-dom"
import { toast } from "sonner"
import { Loader2, Eye, EyeOff, CheckCircle2, Zap } from "lucide-react"
import { Button } from "@hms/shared/components/ui/button"
import { Input } from "@hms/shared/components/ui/input"
import { Label } from "@hms/shared/components/ui/label"

const loginSchema = z.object({
  email: z.string().email("Please enter a valid email address"),
  password: z.string().min(6, "Password must be at least 6 characters"),
})

type LoginFormValues = z.infer<typeof loginSchema>

export default function SplitLogin() {
  const navigate = useNavigate()
  const [showPassword, setShowPassword] = useState(false)

  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
  } = useForm<LoginFormValues>({
    resolver: zodResolver(loginSchema),
  })

  async function onSubmit(data: LoginFormValues) {
    await new Promise((r) => setTimeout(r, 1000))
    localStorage.setItem("access_token", "mock-token")
    localStorage.setItem(
      "user",
      JSON.stringify({ email: data.email, name: data.email.split("@")[0], role: "PATIENT" })
    )
    toast.success("Welcome back!")
    navigate("/dashboard")
  }

  return (
    <div className="flex min-h-svh">
      {/* Left Panel - Dark Branding */}
      <div className="hidden lg:flex lg:w-1/2 bg-zinc-950 text-white flex-col justify-between p-10">
        <div>
          <h1 className="text-3xl font-bold tracking-tight">Welcome Back</h1>
          <p className="mt-2 text-zinc-400">Sign in to continue to your workspace</p>
        </div>

        <div className="space-y-6">
          <div className="flex items-start gap-4">
            <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-zinc-800">
              <CheckCircle2 className="h-5 w-5 text-zinc-300" />
            </div>
            <div>
              <h3 className="font-semibold">Secure Access</h3>
              <p className="text-sm text-zinc-400">
                Your data is protected with enterprise-grade security
              </p>
            </div>
          </div>
          <div className="flex items-start gap-4">
            <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-zinc-800">
              <Zap className="h-5 w-5 text-zinc-300" />
            </div>
            <div>
              <h3 className="font-semibold">Fast Performance</h3>
              <p className="text-sm text-zinc-400">
                Lightning-fast access to all your resources
              </p>
            </div>
          </div>
        </div>

        <p className="text-sm text-zinc-500">
          &copy; {new Date().getFullYear()} Desk. All rights reserved.
        </p>
      </div>

      {/* Right Panel - Login Form */}
      <div className="flex w-full lg:w-1/2 items-center justify-center bg-white p-6 sm:p-10">
        <div className="w-full max-w-md space-y-8">
          <div>
            <h2 className="text-2xl font-bold text-zinc-900">Sign In</h2>
            <p className="mt-1 text-sm text-zinc-500">
              Enter your credentials to access your account
            </p>
          </div>

          <form onSubmit={handleSubmit(onSubmit)} className="space-y-5">
            <div className="space-y-2">
              <Label htmlFor="email" className="text-zinc-700">
                Email
              </Label>
              <Input
                id="email"
                type="email"
                placeholder="name@example.com"
                autoComplete="email"
                className="h-11 rounded-lg border-zinc-300 bg-white text-zinc-900 placeholder:text-zinc-400 focus-visible:border-zinc-900 focus-visible:ring-zinc-900/20"
                aria-invalid={!!errors.email}
                {...register("email")}
              />
              {errors.email && (
                <p className="text-sm text-destructive">{errors.email.message}</p>
              )}
            </div>

            <div className="space-y-2">
              <Label htmlFor="password" className="text-zinc-700">
                Password
              </Label>
              <div className="relative">
                <Input
                  id="password"
                  type={showPassword ? "text" : "password"}
                  placeholder="Enter your password"
                  autoComplete="current-password"
                  className="h-11 rounded-lg border-zinc-300 bg-white pr-10 text-zinc-900 placeholder:text-zinc-400 focus-visible:border-zinc-900 focus-visible:ring-zinc-900/20"
                  aria-invalid={!!errors.password}
                  {...register("password")}
                />
                <button
                  type="button"
                  onClick={() => setShowPassword(!showPassword)}
                  className="absolute right-3 top-1/2 -translate-y-1/2 text-zinc-400 hover:text-zinc-600"
                  tabIndex={-1}
                  aria-label={showPassword ? "Hide password" : "Show password"}
                >
                  {showPassword ? (
                    <EyeOff className="h-4 w-4" />
                  ) : (
                    <Eye className="h-4 w-4" />
                  )}
                </button>
              </div>
              {errors.password && (
                <p className="text-sm text-destructive">{errors.password.message}</p>
              )}
            </div>

            <Button
              type="submit"
              size="lg"
              className="w-full h-11 rounded-lg bg-zinc-900 text-white hover:bg-zinc-800"
              disabled={isSubmitting}
            >
              {isSubmitting && <Loader2 className="animate-spin" />}
              {isSubmitting ? "Signing in..." : "Sign In"}
            </Button>
          </form>

          <p className="text-sm text-zinc-500 text-center">
            Don&apos;t have an account?{" "}
            <Link to="/auth/register" className="text-zinc-900 font-medium hover:underline">
              Register
            </Link>
          </p>
        </div>
      </div>
    </div>
  )
}

Example output

About the author

  • Technology Enthusiast and voracious reader with a demonstrated history of working in the computer software industry. Skilled in PHP, JavaScript, NodeJS, Angular, MySQL, MongoDB, Web3, Product Development, Project Management, and Teamwork.

No comments yet. Be the first to comment.