Contact section
A validated contact form that morphs into a confirmation, support channels, and office cards with local times.
Preview
Contact section preview
Live · keyboard ready
Talk to our team
Questions about licensing, a bug you can't pin down, or a component you wish existed. A person reads every message.
- Replies within one business day
- hello@example.com
When to use
- Contact pages and sections on marketing sites.
- Sales or support pages that list several channels with response times.
- Companies with offices in several time zones.
When not to use
- Use support-widget for an in-app help launcher.
- Use signup-form or login blocks for account flows.
shadcn CLI
Also installs (7)
- manicat-foundation
- avatar
- button
- copy-button
- input
- segmented-control
- textarea
Manual install(+)
registry.jsonjson
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "contact-section",
"type": "registry:block",
"title": "Contact section",
"description": "A validated contact form that morphs into a confirmation, support channels, and office cards with local times.",
"categories": [
"blocks"
],
"dependencies": [
"lucide-react",
"motion"
],
"registryDependencies": [
"https://manicat.viraza.net/r/manicat-foundation.json",
"https://manicat.viraza.net/r/avatar.json",
"https://manicat.viraza.net/r/button.json",
"https://manicat.viraza.net/r/copy-button.json",
"https://manicat.viraza.net/r/input.json",
"https://manicat.viraza.net/r/segmented-control.json",
"https://manicat.viraza.net/r/textarea.json"
],
"files": [
{
"path": "registry/blocks/contact-section/contact-section.tsx",
"type": "registry:component",
"target": "@components/manicat/blocks/contact-section/contact-section.tsx"
},
{
"path": "registry/blocks/contact-section/contact-section.module.css",
"type": "registry:component",
"target": "@components/manicat/blocks/contact-section/contact-section.module.css"
},
{
"path": "lib/media.ts",
"type": "registry:lib",
"target": "@components/manicat/lib/media.ts"
},
{
"path": "registry/components/textarea/textarea.tsx",
"type": "registry:component",
"target": "@components/manicat/textarea/textarea.tsx"
},
{
"path": "registry/components/textarea/textarea.module.css",
"type": "registry:component",
"target": "@components/manicat/textarea/textarea.module.css"
},
{
"path": "registry/components/segmented-control/segmented-control.tsx",
"type": "registry:component",
"target": "@components/manicat/segmented-control/segmented-control.tsx"
},
{
"path": "registry/components/segmented-control/segmented-control.module.css",
"type": "registry:component",
"target": "@components/manicat/segmented-control/segmented-control.module.css"
},
{
"path": "registry/components/input/input.tsx",
"type": "registry:component",
"target": "@components/manicat/input/input.tsx"
},
{
"path": "registry/components/input/input.module.css",
"type": "registry:component",
"target": "@components/manicat/input/input.module.css"
},
{
"path": "registry/components/copy-button/copy-button.tsx",
"type": "registry:component",
"target": "@components/manicat/copy-button/copy-button.tsx"
},
{
"path": "registry/components/copy-button/copy-button.module.css",
"type": "registry:component",
"target": "@components/manicat/copy-button/copy-button.module.css"
},
{
"path": "lib/use-copy-feedback.ts",
"type": "registry:lib",
"target": "@components/manicat/lib/use-copy-feedback.ts"
},
{
"path": "registry/components/button/button.tsx",
"type": "registry:component",
"target": "@components/manicat/button/button.tsx"
},
{
"path": "registry/components/button/button.module.css",
"type": "registry:component",
"target": "@components/manicat/button/button.module.css"
},
{
"path": "registry/components/avatar/avatar.tsx",
"type": "registry:component",
"target": "@components/manicat/avatar/avatar.tsx"
},
{
"path": "registry/components/avatar/avatar.module.css",
"type": "registry:component",
"target": "@components/manicat/avatar/avatar.module.css"
}
],
"docs": "Docs and live preview: https://uiarc.dev/components/blocks/contact-section",
"meta": {
"tier": "free",
"kind": "block",
"docs": "https://manicat.viraza.net/components/blocks/contact-section",
"markdown": "https://uiarc.dev/components/blocks/contact-section/markdown"
}
}Usage
Install the component, then copy this into your app. Change the content and the props to fit your screen.
example.tsxtsx
"use client";
import { ContactSection } from "manicat/registry/blocks/contact-section/contact-section";
export function ContactSectionExample() {
// Size containers have no width of their own: give the demo the whole row.
return <div className="w-full"><ContactSection /></div>;
}
Examples
Real screens rather than isolated props. Switch to Code to copy a whole example into your project.
Contact form A form with topics; onSubmit receives the message.
Contact form
A form with topics; onSubmit receives the message. preview
Live · keyboard ready
Talk to us
We usually answer within one business day.
- Replies within one business day
- hello@example.com
contact-form-a-form-with-topics-onsubmit-receives-the-message-.tsxtsx
"use client";
import { ContactSection } from "manicat/registry/blocks/contact-section/contact-section";
export function ContactSectionFormExample() {
return (
<ContactSection
variant="form"
title="Talk to us"
description="We usually answer within one business day."
topics={["Sales", "Support", "Press"]}
onSubmit={async (message) => console.log(message)}
/>
);
}
Keyboard interactions
| Keys | Action |
|---|---|
| Arrow keys | Move between topic chips, which form a radio group. |
Accessibility
- Fields use labelled Arc Input and Textarea; errors appear after the first submit and update as you type.
- A failed send shows a role="alert" message and keeps the form.
- Office open status is written out, not shown by color alone.
Motion
- The form card springs into the confirmation; faces slide along one axis in the direction of travel out of a soft blur.
- The topic highlight glides between chips.
- Reduced motion swaps faces without travel.
Responsive behavior
- Container queries: below 820px the form layout stacks and the channel list becomes a horizontal scrolling row; below 520px field rows stack and the submit button fills the width.
Performance
- The offices variant re-renders every 15 seconds to keep local times live; other variants have no timers.
Notes for AI
- Without onSubmit the form only simulates sending; always wire it in production.
- Offices compute local time and open status with Intl.DateTimeFormat in each timeZone.
- Composes Arc Input, Textarea, Button, CopyButton, SegmentedControl, and Avatar.