Stackbits
Components > Contact Section

Contact Section

The Contact Section is a dynamic and interactive component designed to enhance user engagement by providing direct links to various social media platforms and contact methods. It features smooth animations and responsive design, ensuring a seamless experience across devices.

Preview

Follow below steps 👇🏻

Install dependencies

1
npm i framer-motion

Component

Create a file contact-section.tsx in your components folder and paste this code

1
'use client';
2
3
import { ReactNode, useState } from 'react';
4
import { AnimatePresence, motion } from 'framer-motion';
5
import Link from 'next/link';
6
7
type ContactType = {
8
name: string;
9
id: string;
10
logo: ReactNode;
11
message: string;
12
link: string;
13
};
14
15
const ContactSection = ({ contacts }: { contacts: ContactType[] }) => {
16
const [hovered, setHovered] = useState<string | null>(null);
17
18
return (
19
<div className="max-w-[600px] flex flex-col gap-4 w-full items-start justify-start">
20
<div className="flex sm:p-10 font-bold text-4xl w-full h-[300px] sm:h-[400px] rounded-3xl border-white/20 relative border-[1px] items-center justify-center">
21
<div
22
style={{
23
perspective: '1000px',
24
transform: 'rotateZ(-10deg) rotateY(25deg) rotateX(30deg)'
25
}}
26
className="h-[100px] sm:h-[150px] w-[95%] sm:w-[90%] bg-white/10 border-2 border-white/10 shadow-inner shadow-black/40 rounded-3xl flex items-center justify-center overflow-hidden"
27
>
28
<AnimatePresence mode="popLayout">
29
{contacts.map((contact) => {
30
return (
31
contact.name === hovered && (
32
<motion.div
33
key={contact.name + contact.id}
34
initial={{
35
opacity: 0,
36
y: 100
37
}}
38
animate={{
39
opacity: 1,
40
y: 0
41
}}
42
exit={{
43
opacity: 0,
44
y: -100
45
}}
46
className="absolute inset-0 w-full h-full flex items-center justify-start whitespace-nowrap p-5 text-white"
47
>
48
<p className="text-xl sm:text-2xl">{contact.id}</p>
49
</motion.div>
50
)
51
);
52
})}
53
</AnimatePresence>
54
</div>
55
<AnimatePresence mode="popLayout">
56
{contacts.map((contact) => {
57
return (
58
contact.name === hovered && (
59
<motion.div
60
key={contact.name + contact.id + contact.logo + contact.message}
61
initial={{
62
opacity: 0
63
}}
64
animate={{
65
opacity: 1
66
}}
67
exit={{
68
opacity: 0
69
}}
70
className="absolute bottom-0 w-full flex items-center justify-start whitespace-nowrap p-5 text-sm md:text-base max-w-[1000px] text-white/85"
71
>
72
<p>{contact.message}</p>
73
</motion.div>
74
)
75
);
76
})}
77
</AnimatePresence>
78
</div>
79
80
<div className="flex items-center justify-start w-full">
81
{contacts.map((contact) => {
82
return (
83
<Link key={contact.id + contact.link} href={contact.link} target="_blank">
84
<motion.div
85
initial={{
86
y: 0,
87
scale: 1
88
}}
89
whileHover={{
90
y: -10,
91
scale: 1.1
92
}}
93
className="cursor-pointer p-3 shrink-0"
94
onTouchStart={() => setHovered(contact.name)}
95
onTouchEnd={() => setHovered(null)}
96
onMouseEnter={() => setHovered(contact.name)}
97
onMouseLeave={() => setHovered(null)}
98
>
99
{contact.logo}
100
</motion.div>
101
</Link>
102
);
103
})}
104
</div>
105
</div>
106
);
107
};
108
109
export default ContactSection;

Usage

1
<ContactSection
2
contacts={[
3
{
4
name: 'Gmail',
6
link: 'mailto:[email protected]',
7
logo: <Mail />,
8
message: '100% chance I respond.'
9
},
10
{
11
name: 'X',
12
id: 'samitkapoorr',
13
link: 'https://x.com/samitkapoorr',
14
logo: <Twitter />,
15
message: '100% chance I respond.'
16
},
17
{
18
name: 'Linkedin',
19
id: 'Samit Kapoor',
20
link: 'https://linkedin.com/in/samit-kapoor',
21
logo: <Linkedin />,
22
message: "Can't promise a timely reply."
23
},
24
{
25
name: 'Instagram',
26
id: 'im_samit',
27
link: 'https://instagram.com/im_samit',
28
logo: <Instagram />,
29
message: "If I see it, I'll respond."
30
},
31
{
32
name: 'Github',
33
id: 'samitkapoor',
34
link: 'https://github.com/samitkapoor',
35
logo: <Github />,
36
message: "You can't text me here, but maybe follow?"
37
}
38
]}
39
/>

⭐️ Got a question or feedback?
Feel free to reach out!