# Split Sign-In With Brand Panel

> Two-column sign-in pairing a dark brand panel that lists product features with a plain email and password form, no social login buttons.

A shadcn/ui block from the [@7ovr](https://7ovr.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/7ovr/auth-2).

- Page, with a live preview: https://shadcn.exchange/r/7ovr/auth-2
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/7ovr/auth-2-light-7c35d417b8ac26d6.png
- Registry item: https://7ovr.com/r/auth-2.json
- Categories: auth
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://7ovr.com/r/auth-2.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@base-ui/react`, `zod`
- Registry items: `button`, `checkbox`, `field`, `input`, `sonner`

## Notes from the registry

Requires a `base-*` style in components.json (the `shadcn init` default). Legacy `new-york`/`radix-*` styles install Radix primitives, which reject the `render` prop this block uses.

## Files

### `registry/blocks/auth/2/auth-block.tsx`

```tsx
"use client"

import { useState } from "react"
import { toast } from "sonner"
import { z } from "zod"

import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import {
  Field,
  FieldDescription,
  FieldError,
  FieldGroup,
  FieldLabel,
} from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import { Toaster } from "@/components/ui/sonner"
import { IconPlaceholder } from "@/components/icons/icon-placeholder"

const BRAND = "Acme"
const TAGLINE = "Collaborative work, simplified."
const FEATURES = [
  "Real-time project dashboards",
  "Role-based access control",
  "Audit logs & compliance reports",
]

const signInSchema = z.object({
  email: z
    .string()
    .min(1, "Email is required")
    .email("Enter a valid email address"),
  password: z.string().min(8, "Password must be at least 8 characters"),
})

export default function AuthBlock() {
  const [errors, setErrors] = useState<Record<string, string>>({})

  function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault()
    const data = Object.fromEntries(new FormData(event.currentTarget))
    const result = signInSchema.safeParse(data)
    if (!result.success) {
      const next: Record<string, string> = {}
      for (const issue of result.error.issues) {
        const key = issue.path[0]
        if (typeof key === "string" && !next[key]) {
          next[key] = issue.message
        }
      }
      setErrors(next)
      return
    }
    setErrors({})
    toast.promise(new Promise((resolve) => setTimeout(resolve, 1400)), {
      loading: "Signing you in…",
      success: "Welcome back to Acme!",
      error: "Sign-in failed. Please try again.",
    })
  }

  function clearError(name: string) {
    setErrors((prev) => {
      if (!prev[name]) return prev
      const next = { ...prev }
      delete next[name]
      return next
    })
  }

  return (
    <section className="flex w-full items-center justify-center bg-background text-foreground">
      <Toaster />
      <div className="flex w-full max-w-4xl flex-col overflow-hidden rounded-xl md:flex-row">
        <div className="dark flex flex-col justify-between gap-10 bg-background px-10 py-12 text-foreground md:w-1/2">
          <div>
            <span className="text-xl font-bold tracking-tight">{BRAND}</span>
          </div>
          <div className="flex flex-col gap-6">
            <p className="font-heading text-3xl leading-tight font-bold tracking-tight">
              {TAGLINE}
            </p>
            <ul className="flex flex-col gap-3">
              {FEATURES.map((f) => (
                <li
                  key={f}
                  className="flex items-center gap-3 text-sm text-foreground/80"
                >
                  <span className="flex size-5 shrink-0 items-center justify-center rounded-md border border-foreground/30 bg-foreground/10 text-foreground">
                    <IconPlaceholder
                      lucide="Check"
                      tabler="IconCheck"
                      hugeicons="Tick02Icon"
                      phosphor="Check"
                      remixicon="RiCheckLine"
                      className="size-3.5"
                      aria-hidden="true"
                    />
                  </span>
                  {f}
                </li>
              ))}
            </ul>
          </div>
          <p className="text-xs text-foreground/50">
            © <span suppressHydrationWarning>{new Date().getFullYear()}</span>{" "}
            {BRAND} Inc. All rights reserved.
          </p>
        </div>

        <div className="flex flex-col justify-center gap-8 border border-border bg-card px-10 py-12 md:w-1/2">
          <div className="flex flex-col gap-1">
            <h1 className="font-heading text-xl font-bold tracking-tight">
              Sign in
            </h1>
            <p className="text-sm text-muted-foreground">
              Enter your credentials to access your workspace.
            </p>
          </div>

          <form
            className="flex flex-col gap-6"
            onSubmit={handleSubmit}
            noValidate
          >
            <FieldGroup>
              <Field>
                <FieldLabel htmlFor="email">Email address</FieldLabel>
                <div className="relative">
                  <IconPlaceholder
                    lucide="Mail"
                    tabler="IconMail"
                    hugeicons="MailIcon"
                    phosphor="Envelope"
                    remixicon="RiMailLine"
                    className="pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-foreground"
                    aria-hidden="true"
                  />
                  <Input
                    id="email"
                    name="email"
                    type="email"
                    placeholder="name@company.com"
                    className="pl-8"
                    autoComplete="email"
                    aria-invalid={!!errors.email}
                    onChange={() => clearError("email")}
                  />
                </div>
                <FieldError>{errors.email}</FieldError>
              </Field>

              <Field>
                <div className="flex items-center justify-between">
                  <FieldLabel htmlFor="password">Password</FieldLabel>
                  <Button
                    variant="link"
                    size="xs"
                    className="h-auto p-0 text-xs"
                    render={<a href="#" />}
                    nativeButton={false}
                  >
                    Forgot Password?
                  </Button>
                </div>
                <div className="relative">
                  <IconPlaceholder
                    lucide="Lock"
                    tabler="IconLockPassword"
                    hugeicons="LockPasswordIcon"
                    phosphor="Lock"
                    remixicon="RiLockPasswordLine"
                    className="pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-foreground"
                    aria-hidden="true"
                  />
                  <Input
                    id="password"
                    name="password"
                    type="password"
                    placeholder="••••••••"
                    className="pl-8"
                    autoComplete="current-password"
                    aria-invalid={!!errors.password}
                    onChange={() => clearError("password")}
                  />
                </div>
                {errors.password ? (
                  <FieldError>{errors.password}</FieldError>
                ) : (
                  <FieldDescription>
                    Must be at least 8 characters.
                  </FieldDescription>
                )}
              </Field>

              <Field orientation="horizontal">
                <FieldLabel
                  htmlFor="remember"
                  className="font-normal text-muted-foreground"
                >
                  <Checkbox id="remember" name="remember" />
                  Keep me signed in
                </FieldLabel>
              </Field>
            </FieldGroup>

            <Button type="submit" className="w-full" size="lg">
              Sign In
            </Button>
          </form>

          <p className="text-center text-xs text-muted-foreground">
            By signing in you agree to our{" "}
            <Button
              variant="link"
              className="h-auto p-0 text-xs"
              render={<a href="#" />}
              nativeButton={false}
            >
              Terms of Service
            </Button>{" "}
            and{" "}
            <Button
              variant="link"
              className="h-auto p-0 text-xs"
              render={<a href="#" />}
              nativeButton={false}
            >
              Privacy Policy
            </Button>
            .
          </p>
        </div>
      </div>
    </section>
  )
}
```
