Contact card
Contact card with a form beside contact details.
Usage
import { ContactDesk } from '@/components/blocks/contact-04'
<ContactDesk />
// Send the form to your own endpoint
<ContactDesk
onSubmit={async (values) => {
const response = await fetch('/api/contact', {
method: 'POST',
body: JSON.stringify(values),
})
if (!response.ok) throw new Error('We could not send your message. Please try again.')
}}
/>
// Your own copy, details and fields
<ContactDesk
title="Get in touch"
details={[
{ label: 'Email', value: 'hello@acme.example', href: 'mailto:hello@acme.example' },
{ label: 'Office', value: '12 Harbour Road, Bristol BS1 5TT' },
]}
socials={[{ label: 'Acme on X', href: '#', icon: 'x' }]}
fields={[
{ name: 'name', label: 'Full name', autoComplete: 'name', required: true, width: 'half' },
{ name: 'phone', label: 'Phone', kind: 'tel', autoComplete: 'tel', width: 'half' },
{ name: 'message', label: 'Message', kind: 'textarea', required: true, minLength: 10 },
]}
/>
Install
pnpm dlx shadcn@latest add @pastaui-pro/contact-04npx shadcn@latest add @pastaui-pro/contact-04yarn dlx shadcn@latest add @pastaui-pro/contact-04bunx --bun shadcn@latest add @pastaui-pro/contact-04Source
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | = 'Get a reply from a real person' | Card heading. |
| description | string | = 'Planning a rollout, moving from another tool or looking to team up?…' | Intro under the heading. Pass an empty string to hide it. |
| details | ContactDeskDetail[] | = Email, phone and office | Rows in the side column, each with a label, a value and an optional href (mailto:, tel: or a map link). |
| socialsLabel | string | = 'Elsewhere' | Label above the social buttons, also used as the nav name. |
| socials | ContactDeskSocial[] | = X, Instagram, Pinterest and YouTube | Round social buttons, each with a label (the accessible name), an href and an icon: 'x', 'instagram', 'pinterest' or 'youtube'. Pass an empty array to hide them. |
| fields | ContactDeskField[] | = Name, email, organisation, reason and details | Form fields, each with a name, label, kind ('text', 'email', 'tel', 'select' or 'textarea'), placeholder, required, autoComplete, options, minLength, maxLength (adds a counter to textareas) and width ('full' or 'half'). |
| submitLabel | string | = 'Send enquiry' | Submit button text. |
| responseNote | string | = 'Most enquiries get an answer within hours.' | Short note beside the submit button. Pass an empty string to hide it. |
| successTitle | string | = 'Enquiry sent' | Heading of the confirmation panel, which receives focus after sending. |
| successMessage | string | = 'Thank you. A specialist will write back…' | Text under the confirmation heading. |
| onSubmit | (values: Record<string, string>) => void | Promise<void> | = Simulated success after 1.1s | Receives the trimmed values once every field is valid. Throw an Error to show its message in the error state. |
| className | string | = — | Extra classes for the section. |
| style | CSSProperties | = — | Inline styles, handy for overriding the --pp-* theme variables. |