Contact Channel Cards
A free React contact section with clear routes, response times, and pointer-aware depth.
Choose the right team
Start with the right conversation
Tell us what you are working towards. Each route goes straight to the people best placed to help.
- Talk to salesShape the right plan for a new product, a growing team, or a considered migration.Replies within one business day
- Get product supportBring a technical question, a tricky implementation, or the details of an issue in production.First response within four hours
- Explore a partnershipDiscuss integrations, editorial collaborations, or a shared launch with our partnerships team.Replies within two business days
- Contact the press deskRequest product context, company facts, or a conversation with the team behind the work.Replies within one business day
- Ask about careersLearn how we work, what we value, and where your craft could make the next release stronger.Replies within three business days
- Report a security concernShare a responsible disclosure directly with the team that can investigate and respond.Acknowledged within one business day
Customise
Code
<ContactChannelCards
title={
"Start with the right " +
"conversation"
}
description={
"Tell us what you are " +
"working towards. Each " +
"route goes straight to " +
"the people best placed " +
"to help."
}
channels={channels}
/>Contact Channel Cards is a free React contact section for Next.js, built with Motion and styled with Tailwind. It presents two to six full-card contact links in a responsive list, so visitors can choose sales, support, partnerships, or another team while seeing the response expectation before they leave the page.
Every destination is a real anchor with its label, explanation, and expectation present in the server HTML. Cards reveal once as the section enters view, then fine pointers add spring-smoothed tilt and a local glow without React pointer renders. Touch users keep a static pressed state, keyboard focus receives a centred emphasis without rotation, and reduced motion keeps every card visible and still.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/contact-channel-cardsUsage
import { ContactChannelCards } from "@/components/contact-channel-cards";
const channels = [
{
id: "sales",
label: "Talk to sales",
description: "Shape the right plan for your product and team.",
expectation: "Replies within one business day",
href: "/contact/sales",
},
{
id: "support",
label: "Get product support",
description: "Bring a technical question or production issue.",
expectation: "First response within four hours",
href: "/support",
},
];
export function ContactPage() {
return (
<ContactChannelCards
title="Start with the right conversation"
description="Choose the team best placed to help."
channels={channels}
columns={2}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| eyebrow | string | "Choose the right team" | Introductory label rendered above the section heading. |
| title | string | required | Section heading rendered as the single h2. |
| description | string | undefined | Optional supporting copy below the heading. |
| channels | { id: string; label: string; description: string; expectation: string; href: string; icon?: ReactNode }[] | required | Two to six stable-ID destinations rendered as semantic list items and full-card anchors. |
| columns | 2 | 3 | 3 | Desktop grid columns. Mobile always uses one column. |
| revealOffset | number | 18 | Entrance distance in CSS pixels, clamped from 0 to 32. |
| revealStagger | number | 0.07 | Delay between card entrances in seconds, clamped from 0 to 0.14. |
| maxTilt | number | 5 | Maximum fine-pointer rotation in degrees, clamped from 0 to 8. |
| glowSize | number | 240 | Decorative glow diameter in CSS pixels, clamped from 140 to 360. |
| glowLag | number | 0.38 | Glow spring response in seconds, clamped from 0.15 to 0.8. |
| radius | number | 20 | Card radius in CSS pixels, clamped from 8 to 32. |
| className | string | undefined | Additional classes merged onto the section root. |
Customisation
Contact Channel Cards exposes three Tier 3 colour tokens. --contact-channel-surface sets the resting card surface, --contact-channel-glow colours the local and centred highlights, and --contact-channel-border-active controls the hover, focus, and pressed border. Each defaults to a semantic token, so the section follows dark and light themes without component edits:
:root {
--contact-channel-surface: var(--surface);
--contact-channel-glow: var(--primary);
--contact-channel-border-active: var(--ring);
}Frequently asked questions
- Is Contact Channel Cards free for commercial use?
- Yes. Contact Channel Cards is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Is Contact Channel Cards accessible and performant?
- Yes. The section uses one labelled h2, a semantic list, and full-card anchors with visible focus rings and response expectations in the accessible name. The once-only reveal changes transform and opacity, pointer movement writes Motion values instead of React state, and touch and reduced-motion modes install no move handler.
- How do I customise the card effect and colours?
- Use maxTilt, glowSize, glowLag, radius, revealOffset, and revealStagger to tune the geometry and motion. Override the three contact-channel Tier 3 tokens from an ancestor to change the surface, glow, and active border while retaining the semantic theme system.