Contact layouts for a direct message or a few different support routes. Adjust the fields and details to fit your team.
Simple form
A centered form with name, email, and message fields.
tsx
"use client";import { Button } from "@/components/ui/button";import { Input } from "@/components/ui/input";import { Label } from "@/components/ui/label";import { Textarea } from "@/components/ui/textarea";import { cn } from "@/lib/utils";type Contact01Props = { className?: string;};export function Contact01({ className }: Contact01Props) { return ( <section className={cn("@container w-full bg-background", className)}> <div className="mx-auto w-full max-w-md px-4 py-10 @[32rem]:px-6 @[32rem]:py-14"> <div className="text-center"> <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl"> Get in touch </h2> <p className="mt-2 text-sm tracking-wide text-muted-foreground"> Tell us what you’re building — we’ll get back within a day. </p> </div> <form className="mt-8 flex flex-col gap-4" onSubmit={(event) => event.preventDefault()} > <div className="flex flex-col gap-1.5"> <Label htmlFor="contact-01-name">Name</Label> <Input id="contact-01-name" name="name" placeholder="Maya Chen" className="border-0 bg-muted" /> </div> <div className="flex flex-col gap-1.5"> <Label htmlFor="contact-01-email">Email</Label> <Input id="contact-01-email" name="email" type="email" placeholder="maya@northline.com" className="border-0 bg-muted" /> </div> <div className="flex flex-col gap-1.5"> <Label htmlFor="contact-01-message">Message</Label> <Textarea id="contact-01-message" name="message" placeholder="How can we help?" className="min-h-28 max-h-48 resize-y border-0 bg-muted" /> </div> <Button type="submit" size="sm" className="w-full"> Send message </Button> </form> </div> </section> );}Installation
npx @arctis-sh/@arctis-sh/ui@latest add contact-01Usage
import { Contact01 } from "@/components/blocks/contact/contact-01"<Contact01 />Split
Direct email links on the left and a filled form on the right, without extra card chrome.
tsx
"use client";import { Button, buttonVariants } from "@/components/ui/button";import { Input } from "@/components/ui/input";import { Label } from "@/components/ui/label";import { Textarea } from "@/components/ui/textarea";import { cn } from "@/lib/utils";type Contact02Props = { className?: string;};const DETAILS = [ { label: "Email", value: "hello@example.com", href: "mailto:hello@example.com", }, { label: "Support", value: "support@example.com", href: "mailto:support@example.com", },] as const;export function Contact02({ className }: Contact02Props) { return ( <section className={cn("@container w-full bg-background", className)}> <div data-slot="block-split" className="mx-auto flex w-full max-w-4xl flex-col gap-10 px-4 py-10 @[40rem]:flex-row @[40rem]:items-start @[40rem]:gap-10 @[40rem]:px-6 @[40rem]:py-14" > <div className="w-full shrink-0 @[40rem]:w-[40%]"> <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl"> Let’s talk </h2> <p className="mt-2 text-sm tracking-wide text-muted-foreground"> Email us directly or send a note with the form. </p> <ul className="mt-8 flex flex-col gap-5"> {DETAILS.map((detail) => ( <li key={detail.label} className="flex flex-col gap-1"> <p className="text-xs tracking-wide text-muted-foreground"> {detail.label} </p> <a href={detail.href} className={buttonVariants({ variant: "link", size: "sm", className: "justify-start", })} > <span data-slot="button-link-label" className="relative inline after:absolute after:inset-x-0 after:bottom-0 after:h-px after:origin-left after:scale-x-0 after:bg-current after:transition-transform after:duration-200 after:ease-out group-hover/button-link:after:scale-x-100" > {detail.value} </span> </a> </li> ))} </ul> </div> <form className="flex min-w-0 w-full flex-col gap-4 @[40rem]:w-[60%]" onSubmit={(event) => event.preventDefault()} > <div className="grid grid-cols-1 gap-4 @[32rem]:grid-cols-2"> <div className="flex flex-col gap-1.5"> <Label htmlFor="contact-02-first-name">First name</Label> <Input id="contact-02-first-name" name="firstName" placeholder="Jordan" className="border-0 bg-muted" /> </div> <div className="flex flex-col gap-1.5"> <Label htmlFor="contact-02-last-name">Last name</Label> <Input id="contact-02-last-name" name="lastName" placeholder="Hale" className="border-0 bg-muted" /> </div> </div> <div className="flex flex-col gap-1.5"> <Label htmlFor="contact-02-email">Email</Label> <Input id="contact-02-email" name="email" type="email" placeholder="jordan@relay.com" className="border-0 bg-muted" /> </div> <div className="flex flex-col gap-1.5"> <Label htmlFor="contact-02-company">Company</Label> <Input id="contact-02-company" name="company" placeholder="Relay" className="border-0 bg-muted" /> </div> <div className="flex flex-col gap-1.5"> <Label htmlFor="contact-02-message">Message</Label> <Textarea id="contact-02-message" name="message" placeholder="What do you need?" className="min-h-28 max-h-48 resize-y border-0 bg-muted" /> </div> <Button type="submit" size="sm" className="w-full @[32rem]:w-auto @[32rem]:self-start" > Send message </Button> </form> </div> </section> );}Installation
npx @arctis-sh/@arctis-sh/ui@latest add contact-02Usage
import { Contact02 } from "@/components/blocks/contact/contact-02"<Contact02 />Channels
Three support routes with a compact email capture row underneath.
tsx
"use client";import { Button, buttonVariants } from "@/components/ui/button";import { Input } from "@/components/ui/input";import { cn } from "@/lib/utils";type Contact03Props = { className?: string;};const CHANNELS = [ { title: "Sales", description: "Pricing, demos, and enterprise plans.", href: "mailto:sales@example.com", action: "sales@example.com", }, { title: "Support", description: "Help with install, tokens, and blocks.", href: "mailto:support@example.com", action: "support@example.com", }, { title: "Press", description: "Brand assets and interview requests.", href: "mailto:press@example.com", action: "press@example.com", },] as const;export function Contact03({ className }: Contact03Props) { return ( <section className={cn("@container w-full bg-background", className)}> <div className="mx-auto w-full max-w-4xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14"> <div className="mx-auto max-w-md text-center"> <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl"> How can we help? </h2> <p className="mt-2 text-sm tracking-wide text-muted-foreground"> Pick a channel, or leave your email and we’ll follow up. </p> </div> <ul className="mt-8 grid grid-cols-1 gap-3 @[40rem]:grid-cols-3"> {CHANNELS.map((channel) => ( <li key={channel.title} className="flex flex-col rounded-xl bg-muted p-5" > <p className="text-sm font-medium tracking-wide text-foreground"> {channel.title} </p> <p className="mt-1.5 flex-1 text-xs tracking-wide text-muted-foreground"> {channel.description} </p> <a href={channel.href} className={buttonVariants({ variant: "link", size: "sm", className: "mt-4 justify-start", })} > <span data-slot="button-link-label" className="relative inline after:absolute after:inset-x-0 after:bottom-0 after:h-px after:origin-left after:scale-x-0 after:bg-current after:transition-transform after:duration-200 after:ease-out group-hover/button-link:after:scale-x-100" > {channel.action} </span> </a> </li> ))} </ul> <form className="mx-auto mt-6 flex w-full max-w-lg flex-col gap-2 @[32rem]:flex-row @[32rem]:items-center" onSubmit={(event) => event.preventDefault()} > <Input name="email" type="email" placeholder="you@company.com" aria-label="Email" className="h-9 min-h-9 max-h-9 flex-1 border-0 bg-muted py-0" /> <Button type="submit" className="h-9 min-h-9 max-h-9 w-full shrink-0 whitespace-nowrap @[32rem]:w-auto" > Request a callback </Button> </form> </div> </section> );}Installation
npx @arctis-sh/@arctis-sh/ui@latest add contact-03Usage
import { Contact03 } from "@/components/blocks/contact/contact-03"<Contact03 />