Contact form with animated contact info cards, working hours, and interactive icons (Base UI)
@uitripled
@uitripled/react-baseui/src/components/sections/contact-block-baseui.tsx
"use client";
import { Button } from "@base-ui/react/button";
import { Input } from "@base-ui/react/input";
import { motion } from "framer-motion";
import { Mail, MapPin, Phone, Send } from "lucide-react";
const contactInfo = [
{
icon: Mail,
label: "Email",
value: "hello@example.com",
href: "mailto:hello@example.com",
},
{
icon: Phone,
label: "Phone",
value: "+1 (555) 123-4567",
href: "tel:+15551234567",
},
{
icon: MapPin,
label: "Location",
value: "San Francisco, CA",
href: "#",
},
];
export function ContactBlockBaseui() {
return (
<section className="relative w-full overflow-hidden bg-background px-4 py-12 sm:py-16 md:py-20 lg:py-24">
{/* Background Pattern */}
<div className="absolute inset-0 -z-10 h-full w-full bg-white dark:bg-black bg-[linear-gradient(to_right,#8080800a_1px,transparent_1px),linear-gradient(to_bottom,#8080800a_1px,transparent_1px)] bg-[size:14px_24px]"></div>
<div className="mx-auto w-full max-w-6xl">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5 }}
className="mb-12 sm:mb-16 md:mb-20 text-center"
>
<h2 className="mb-4 text-3xl font-bold tracking-tight text-foreground sm:text-4xl md:text-5xl">
Get In Touch
</h2>
<p className="mx-auto max-w-2xl px-4 text-base text-muted-foreground sm:text-lg">
Have a project in mind? Let's discuss how we can work together
</p>
</motion.div>
<div className="grid gap-8 lg:grid-cols-2 lg:gap-12">
{/* Contact Form */}
<motion.div
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.2 }}
>
<div className="relative overflow-hidden rounded-xl border border-border/40 bg-background/60 p-6 backdrop-blur-sm sm:p-8">
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-transparent opacity-50" />
<form className="relative z-10 space-y-6">
<div className="grid gap-6 sm:grid-cols-2">
<div className="space-y-2">
<label
htmlFor="name"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Name
</label>
<Input
id="name"
placeholder="Your name"
className="flex h-10 w-full rounded-md border border-input bg-background/50 px-3 py-2 text-sm ring-offset-background transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus:bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
/>
</div>
<div className="space-y-2">
<label
htmlFor="email"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Email
</label>
<Input
id="email"
type="email"
placeholder="your.email@example.com"
className="flex h-10 w-full rounded-md border border-input bg-background/50 px-3 py-2 text-sm ring-offset-background transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus:bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
/>
</div>
</div>
<div className="space-y-2">
<label
htmlFor="subject"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Subject
</label>
<Input
id="subject"
placeholder="How can I help you?"
className="flex h-10 w-full rounded-md border border-input bg-background/50 px-3 py-2 text-sm ring-offset-background transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus:bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
/>
</div>
<div className="space-y-2">
<label
htmlFor="message"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Message
</label>
<textarea
id="message"
placeholder="Tell me about your project..."
rows={5}
className="flex min-h-[80px] w-full resize-none rounded-md border border-input bg-background/50 px-3 py-2 text-sm ring-offset-background transition-colors placeholder:text-muted-foreground focus:bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
/>
</div>
<Button
type="submit"
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded-md bg-primary px-4 py-2 text-base font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
>
Send Message
<Send className="h-4 w-4" />
</Button>
</form>
</div>
</motion.div>
{/* Contact Info */}
<div className="space-y-6 lg:space-y-8">
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-1">
{contactInfo.map((info, index) => (
<motion.div
key={index}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: index * 0.1 + 0.3, duration: 0.5 }}
>
<div className="group relative overflow-hidden rounded-xl border border-border/40 bg-background/60 p-4 transition-all duration-300 hover:border-foreground/20 hover:shadow-md hover:-translate-y-1 backdrop-blur-sm sm:p-6">
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 via-transparent to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
<a
href={info.href}
className="relative z-10 flex items-center gap-4"
>
<div className="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary transition-colors group-hover:bg-primary group-hover:text-primary-foreground">
<info.icon className="h-5 w-5" />
</div>
<div>
<h3 className="mb-1 font-semibold text-foreground">
{info.label}
</h3>
<p className="text-sm text-muted-foreground transition-colors group-hover:text-foreground/80">
{info.value}
</p>
</div>
</a>
</div>
</motion.div>
))}
</div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: 0.6, duration: 0.5 }}
>
<div className="rounded-xl border border-border/40 bg-background/60 p-6 backdrop-blur-sm sm:p-8">
<h3 className="mb-4 text-xl font-semibold text-foreground">
Working Hours
</h3>
<div className="space-y-3 text-sm text-muted-foreground sm:text-base">
<div className="flex justify-between border-b border-border/40 pb-2">
<span>Monday - Friday</span>
<span className="font-medium text-foreground">
9:00 AM - 6:00 PM
</span>
</div>
<div className="flex justify-between border-b border-border/40 pb-2">
<span>Saturday</span>
<span className="font-medium text-foreground">
10:00 AM - 4:00 PM
</span>
</div>
<div className="flex justify-between pt-1">
<span>Sunday</span>
<span className="font-medium text-foreground">Closed</span>
</div>
</div>
</div>
</motion.div>
</div>
</div>
</div>
</section>
);
}




























