Page Sections

Contact Bar Hero

A hero with a raised contact bar under the headline — one-click email copy, a phone link and a booking button — which can dock to the bottom of the viewport once the hero scrolls away.

Built for service homepages — studios, clinics, consultants — where the visitor's next step is getting in touch. Under the title and subtitle sits a rounded capsule contact bar in three parts: the email (with one-click copy; on success the icon turns into a check and the text reads "Copied" for 1.6 seconds), the phone (a tel: link) and an accent-coloured booking button. With dock on, once the visitor scrolls past the whole hero a compact contact bar springs in at the bottom of the viewport; close it with × and it stays hidden for the rest of the visit. On the right (or below, when centred) is a window-view placeholder you can swap for your own photo.

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add contact-bar-hero.en

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

600
Active edited usageDefault props
<ContactBarHero/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add https://webberui.com/r/contact-bar-hero.en.json

Or, once registries are configured in components.json, install it as @webberui/contact-bar-hero.

Usage

import { ContactBarHero } from "@/components/ui/contact-bar-hero";

<ContactBarHero
  eyebrow="栖木空間|住宅與小店設計"
  title="把光留在家裡,從一通電話開始"
  subtitle="專做 20 坪以下的老屋翻新,三個工作天內回覆初步規劃。"
  email="hello@qimu-studio.example"
  phone="02-2345-6789"
  booking={{ label: "預約諮詢", href: "/booking" }}
  images={[{ src: "/images/studio-window.jpg", alt: "工作室窗邊" }]}
/>

Props

PropTypeDefaultDescription
titleReactNode—Main title (required)
eyebrowReactNode—Small label above the title
subtitleReactNode—Subtitle
primaryActionContactBarHeroAction—Primary CTA under the title (optional, sits alongside the contact bar)
secondaryActionContactBarHeroAction—Secondary CTA under the title
as"h1" | "h2""h1"Heading level used for the title
minHeightnumber560Minimum section height (px)
imagesContactBarHeroImage[]—Media images; only the first is used, and a placeholder is drawn without src
emailstring—Contact email, copyable in one click (required)
phonestring—Contact phone; shown as given, the dial link keeps only digits and +
bookingContactBarHeroAction—Primary booking button at the right end of the contact bar (required)
dockbooleantrueWhether a compact contact bar docks to the bottom of the viewport once the hero scrolls away
dismissedboolean—Controlled: whether the user has closed the dock
defaultDismissedbooleanfalseUncontrolled: initial closed state of the dock
onDismissedChange(dismissed: boolean) => void—Called when the dock's closed state changes
onCopy(email: string) => void—Called after the email is copied successfully
align"left" | "center""left"Text alignment; with left the media sits on the right, with center it sits below
showMediabooleantrueWhether to show the media image
labelsContactBarHeroLabels—Interface string overrides
classNamestring—Passed through to the root section

ContactBarHeroAction

FieldTypeDefaultDescription
labelstring—Button text
hrefstring—Link URL; renders a link when provided
onClick() => void—Click callback; without href it renders a type="button" button

ContactBarHeroImage

FieldTypeDefaultDescription
srcstring—Image URL; when omitted a CSS gradient + SVG placeholder is used
altstring—Alt text

ContactBarHeroLabels

FieldTypeDefaultDescription
copystring"複製" (Copy)Copy button text
copiedstring"已複製" (Copied)Text after a successful copy
copyFailedstring"無法複製" (Copy failed)Text when copying fails
closestring"關閉快速聯絡列" (Close quick contact bar)aria-label of the dock close button
groupstring"聯絡方式" (Contact options)aria-label of the contact bar
dockstring"快速聯絡" (Quick contact)aria-label of the dock

How it works

  • Timing variable: --wb-contact-bar-hero-duration drives both the title group's entrance (600ms when unset) and the contact bar's hover lift (200ms when unset). The accent is --wb-contact-bar-hero-accent (default #0d9488 in light, #2dd4bf in dark); the booking button, eyebrow and focus ring all follow it.
  • Entrance order: eyebrow, title, subtitle and CTAs fade in with y 16→0 in sequence (80ms stagger, cubic-bezier(0.22,1,0.36,1)); 300ms after the title starts, the contact bar rises from y 24 on a spring (stiffness 260, damping 24).
  • Dock trigger: an IntersectionObserver watches the whole section, and the dock appears only once the hero has scrolled entirely above the viewport — a hero still below the fold on page load never triggers it. The closed state supports controlled (dismissed + onDismissedChange) and uncontrolled use.
  • Copy uses navigator.clipboard.writeText; on non-HTTPS origins or when permission is denied it shows the copy-failed text. The dial link strips spaces and hyphens, keeping only digits and +.
  • The component itself uses no vh units; its height comes from the content and minHeight.

Accessibility

  • The root is a <section aria-labelledby> pointing at the title (as picks h1 or h2)
  • The contact bar is role="group" with an aria-label; the dock is an <aside> with its own aria-label
  • The copy button's aria-label includes the full email; the result is announced through a role="status", aria-live="polite" region
  • Icon-only buttons in the dock all carry an aria-label; every button and link has a focus-visible ring, and buttons are type="button"
  • With the system "reduce motion" setting on, the entrance becomes a 150ms fade, the contact bar no longer moves, the hover lift is off, and the dock fades in and out instead of sliding