Team Card
Original · freeA team member card with photo, role and social links.
Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.
npx shadcn@latest add https://webinnoventix.com/r/card-team.json"use client";
import { useState } from "react";
type Social = {
label: string;
href: string;
glyph: "x" | "linkedin" | "github" | "dribbble" | "mail";
};
type Member = {
name: string;
role: string;
team: string;
location: string;
img: string;
bio: string;
status: "online" | "away" | "focus";
socials: Social[];
};
const MEMBERS: Member[] = [
{
name: "Priya Nair",
role: "Principal Design Engineer",
team: "Design Systems",
location: "Bengaluru, IN",
img: "/img/gallery/g07.webp",
bio: "Builds the component library the whole product runs on. Ex-Figma, obsessive about focus states.",
status: "online",
socials: [
{ label: "Priya on X", href: "#", glyph: "x" },
{ label: "Priya on LinkedIn", href: "#", glyph: "linkedin" },
{ label: "Priya on Dribbble", href: "#", glyph: "dribbble" },
{ label: "Email Priya", href: "#", glyph: "mail" },
],
},
{
name: "Marcus Reyes",
role: "Staff Backend Engineer",
team: "Platform",
location: "Austin, US",
img: "/img/gallery/g12.webp",
bio: "Owns the billing pipeline and the parts of the graph nobody else wants to touch.",
status: "focus",
socials: [
{ label: "Marcus on GitHub", href: "#", glyph: "github" },
{ label: "Marcus on LinkedIn", href: "#", glyph: "linkedin" },
{ label: "Email Marcus", href: "#", glyph: "mail" },
],
},
{
name: "Sofia Lindqvist",
role: "Head of Product",
team: "Leadership",
location: "Stockholm, SE",
img: "/img/gallery/g23.webp",
bio: "Turns a wall of customer calls into a roadmap. Believes in shipping small, often, and on purpose.",
status: "away",
socials: [
{ label: "Sofia on X", href: "#", glyph: "x" },
{ label: "Sofia on LinkedIn", href: "#", glyph: "linkedin" },
{ label: "Email Sofia", href: "#", glyph: "mail" },
],
},
];
const STATUS: Record<
Member["status"],
{ dot: string; ring: string; text: string; label: string }
> = {
online: {
dot: "bg-emerald-500",
ring: "ring-emerald-500/30",
text: "text-emerald-600 dark:text-emerald-400",
label: "Available",
},
focus: {
dot: "bg-violet-500",
ring: "ring-violet-500/30",
text: "text-violet-600 dark:text-violet-400",
label: "In focus",
},
away: {
dot: "bg-amber-500",
ring: "ring-amber-500/30",
text: "text-amber-600 dark:text-amber-400",
label: "Away",
},
};
function Glyph({ name }: { name: Social["glyph"] }) {
const common = "h-4 w-4";
switch (name) {
case "x":
return (
<svg viewBox="0 0 24 24" fill="currentColor" className={common} aria-hidden="true">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24h-6.657l-5.214-6.817-5.966 6.817H1.68l7.73-8.835L1.254 2.25h6.826l4.713 6.231 5.451-6.231Zm-1.161 17.52h1.833L7.084 4.126H5.117L17.083 19.77Z" />
</svg>
);
case "linkedin":
return (
<svg viewBox="0 0 24 24" fill="currentColor" className={common} aria-hidden="true">
<path d="M20.45 20.45h-3.56v-5.57c0-1.33-.02-3.04-1.85-3.04-1.85 0-2.14 1.45-2.14 2.94v5.67H9.35V9h3.42v1.56h.05c.48-.9 1.64-1.85 3.37-1.85 3.6 0 4.27 2.37 4.27 5.46v6.28ZM5.34 7.43a2.07 2.07 0 1 1 0-4.14 2.07 2.07 0 0 1 0 4.14ZM7.12 20.45H3.55V9h3.57v11.45ZM22.23 0H1.77C.79 0 0 .77 0 1.73v20.54C0 23.22.79 24 1.77 24h20.46c.98 0 1.77-.78 1.77-1.73V1.73C24 .77 23.21 0 22.23 0Z" />
</svg>
);
case "github":
return (
<svg viewBox="0 0 24 24" fill="currentColor" className={common} aria-hidden="true">
<path d="M12 .5A11.5 11.5 0 0 0 .5 12a11.5 11.5 0 0 0 7.86 10.92c.58.11.79-.25.79-.56v-2c-3.2.7-3.88-1.37-3.88-1.37-.53-1.34-1.29-1.7-1.29-1.7-1.05-.72.08-.7.08-.7 1.16.08 1.77 1.2 1.77 1.2 1.03 1.77 2.71 1.26 3.37.96.1-.75.4-1.26.73-1.55-2.56-.29-5.25-1.28-5.25-5.7 0-1.26.45-2.29 1.19-3.1-.12-.29-.52-1.46.11-3.05 0 0 .97-.31 3.18 1.18a11 11 0 0 1 5.79 0c2.2-1.49 3.17-1.18 3.17-1.18.63 1.59.23 2.76.11 3.05.74.81 1.19 1.84 1.19 3.1 0 4.43-2.7 5.4-5.27 5.69.41.36.78 1.06.78 2.14v3.17c0 .31.21.68.8.56A11.5 11.5 0 0 0 23.5 12 11.5 11.5 0 0 0 12 .5Z" />
</svg>
);
case "dribbble":
return (
<svg viewBox="0 0 24 24" fill="currentColor" className={common} aria-hidden="true">
<path d="M12 0a12 12 0 1 0 0 24 12 12 0 0 0 0-24Zm7.93 5.53a10.16 10.16 0 0 1 2.3 6.36c-.34-.07-3.72-.76-7.12-.33-.07-.17-.14-.35-.22-.53-.21-.5-.44-1-.68-1.48 3.77-1.54 5.48-3.75 5.72-4.02ZM12 1.79c2.57 0 4.92.96 6.71 2.55-.2.28-1.74 2.35-5.38 3.72a48.5 48.5 0 0 0-3.87-6.03A10.3 10.3 0 0 1 12 1.79ZM7.5 2.72a56 56 0 0 1 3.83 5.95c-4.83 1.28-9.1 1.26-9.56 1.26A10.24 10.24 0 0 1 7.5 2.72ZM1.77 12.01v-.31c.44.01 5.46.07 10.62-1.48.3.58.58 1.17.83 1.76l-.4.11c-5.34 1.72-8.18 6.43-8.42 6.83a10.2 10.2 0 0 1-2.63-6.91Zm10.23 10.2c-2.3 0-4.42-.77-6.11-2.07.19-.39 2.3-4.47 8.15-6.51l.07-.02a42.7 42.7 0 0 1 2.19 7.78 10.16 10.16 0 0 1-4.3.82Zm6.03-1.78c-.12-.72-.66-3.64-1.99-7.34 3.2-.51 6.01.32 6.36.44a10.22 10.22 0 0 1-4.37 6.9Z" />
</svg>
);
case "mail":
return (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className={common} aria-hidden="true">
<rect x="3" y="5" width="18" height="14" rx="2.5" />
<path d="m4 7 8 6 8-6" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
}
}
function SocialButton({ social }: { social: Social }) {
return (
<a
href={social.href}
target="_blank"
rel="noopener"
aria-label={social.label}
className="inline-flex h-9 w-9 items-center justify-center rounded-xl border border-slate-200 bg-white text-slate-500 transition-[transform,color,background-color,border-color] duration-200 hover:-translate-y-0.5 hover:border-indigo-300 hover:bg-indigo-50 hover:text-indigo-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white active:translate-y-0 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-400 dark:hover:border-indigo-500/50 dark:hover:bg-indigo-500/10 dark:hover:text-indigo-300 dark:focus-visible:ring-offset-zinc-900"
>
<Glyph name={social.glyph} />
</a>
);
}
function TeamCard({ member }: { member: Member }) {
const [followed, setFollowed] = useState(false);
const s = STATUS[member.status];
return (
<article className="group relative flex w-full flex-col overflow-hidden rounded-3xl border border-slate-200 bg-white shadow-sm transition-shadow duration-300 hover:shadow-xl hover:shadow-slate-900/5 dark:border-zinc-800 dark:bg-zinc-900 dark:hover:shadow-black/40">
<div className="pointer-events-none absolute inset-x-0 top-0 h-28 bg-gradient-to-b from-indigo-500/10 via-violet-500/5 to-transparent dark:from-indigo-500/15 dark:via-violet-500/[0.07]" />
<div className="relative flex flex-col items-center px-6 pt-8">
<div className={`relative rounded-full p-1 ring-2 ${s.ring}`}>
<div className="overflow-hidden rounded-full">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={member.img}
alt={`Portrait of ${member.name}`}
loading="lazy"
draggable={false}
className="ct-avatar h-24 w-24 rounded-full object-cover"
/>
</div>
<span
className={`absolute bottom-1 right-1 h-4 w-4 rounded-full border-2 border-white ${s.dot} dark:border-zinc-900`}
aria-hidden="true"
/>
</div>
<div className="mt-4 flex flex-col items-center text-center">
<h3 className="text-lg font-semibold tracking-tight text-slate-900 dark:text-white">
{member.name}
</h3>
<p className="mt-0.5 text-sm font-medium text-indigo-600 dark:text-indigo-400">
{member.role}
</p>
<div className="mt-2 flex flex-wrap items-center justify-center gap-1.5 text-xs">
<span className="inline-flex items-center gap-1 rounded-full bg-slate-100 px-2.5 py-1 font-medium text-slate-600 dark:bg-zinc-800 dark:text-zinc-300">
{member.team}
</span>
<span className={`inline-flex items-center gap-1 rounded-full px-2.5 py-1 font-medium ${s.text}`}>
<span className={`h-1.5 w-1.5 rounded-full ${s.dot}`} aria-hidden="true" />
{s.label}
</span>
</div>
</div>
</div>
<p className="mt-4 px-6 text-center text-sm leading-relaxed text-slate-500 dark:text-zinc-400">
{member.bio}
</p>
<div className="mt-4 flex items-center justify-center gap-1.5 px-6 text-xs text-slate-400 dark:text-zinc-500">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="h-3.5 w-3.5" aria-hidden="true">
<path d="M12 21s-7-5.2-7-11a7 7 0 0 1 14 0c0 5.8-7 11-7 11Z" strokeLinejoin="round" />
<circle cx="12" cy="10" r="2.5" />
</svg>
{member.location}
</div>
<div className="mt-6 flex items-center justify-between gap-3 border-t border-slate-100 px-6 py-4 dark:border-zinc-800">
<div className="flex items-center gap-1.5">
{member.socials.map((soc) => (
<SocialButton key={soc.label} social={soc} />
))}
</div>
<button
type="button"
onClick={() => setFollowed((v) => !v)}
aria-pressed={followed}
className={`inline-flex items-center gap-1.5 rounded-xl px-3.5 py-2 text-sm font-semibold transition-[transform,background-color,color,border-color] duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white active:scale-[0.97] dark:focus-visible:ring-offset-zinc-900 ${
followed
? "bg-slate-900 text-white ring-slate-900 focus-visible:ring-slate-500 dark:bg-white dark:text-zinc-900 dark:focus-visible:ring-zinc-400"
: "border border-indigo-200 bg-indigo-50 text-indigo-700 hover:bg-indigo-100 focus-visible:ring-indigo-500 dark:border-indigo-500/30 dark:bg-indigo-500/10 dark:text-indigo-300 dark:hover:bg-indigo-500/20"
}`}
>
{followed ? (
<>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" className="h-4 w-4" aria-hidden="true">
<path d="m5 12 4.5 4.5L19 7" strokeLinecap="round" strokeLinejoin="round" />
</svg>
Following
</>
) : (
<>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" className="h-4 w-4" aria-hidden="true">
<path d="M12 5v14M5 12h14" strokeLinecap="round" />
</svg>
Follow
</>
)}
</button>
</div>
</article>
);
}
export default function CardTeam() {
return (
<section className="relative w-full bg-slate-50 px-4 py-20 dark:bg-zinc-950 sm:px-6 lg:px-8">
<style>{`
@keyframes ct-rise {
from { opacity: 0; transform: translateY(14px); }
to { opacity: 1; transform: translateY(0); }
}
.ct-rise { animation: ct-rise 0.6s cubic-bezier(0.22,1,0.36,1) both; }
.group:hover .ct-avatar { transform: scale(1.04); }
.ct-avatar { transition: transform 0.4s cubic-bezier(0.22,1,0.36,1); }
@media (prefers-reduced-motion: reduce) {
.ct-rise { animation: none; }
.ct-avatar { transition: none; }
.group:hover .ct-avatar { transform: none; }
}
`}</style>
<div className="mx-auto max-w-6xl">
<div className="mx-auto max-w-2xl text-center">
<span className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3 py-1 text-xs font-medium text-slate-500 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-400">
<span className="h-1.5 w-1.5 rounded-full bg-emerald-500" aria-hidden="true" />
The people behind the product
</span>
<h2 className="mt-4 text-3xl font-bold tracking-tight text-slate-900 dark:text-white sm:text-4xl">
Meet the team
</h2>
<p className="mt-3 text-base leading-relaxed text-slate-500 dark:text-zinc-400">
A small crew that ships. Follow along, or say hello on any channel.
</p>
</div>
<div className="mt-14 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{MEMBERS.map((member, i) => (
<div
key={member.name}
className="ct-rise"
style={{ animationDelay: `${i * 90}ms` }}
>
<TeamCard member={member} />
</div>
))}
</div>
</div>
</section>
);
}Dependencies
Licence
Built by Web Innoventix. Free for personal and commercial use, no attribution required.
Built by Web Innoventix
Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.
Get a free quoteSimilar components
Browse all →
3D Tilt Cards
OriginalA responsive grid of cards that tilt in 3D toward your cursor with a light glare and lifted depth layers, powered by Framer Motion springs.

Spotlight Follow Cards
OriginalFeature cards where a soft radial spotlight and a glowing border chase the cursor on hover, with a staggered scroll reveal and an animated shimmer line.

3D Flip Cards
OriginalPricing-style cards that flip in 3D on hover or tap to reveal details on the back, keyboard accessible with a staggered entrance animation.

Animated Gradient Border Cards
OriginalCards wrapped in a live conic gradient border that rotates and speeds up on hover, with a shimmer sweep and a scrolling tag marquee.

Glow Effect Card
primitivesA reusable glow effect card for React and Tailwind, with hover and motion.

Neon Gradient Card
gradient-card.tsxA reusable neon gradient card for React and Tailwind, with hover and motion.

Spotlight Magic Card
card.tsxA reusable spotlight magic card for React and Tailwind, with hover and motion.

Tilt Spotlight Card
primitivesA reusable tilt spotlight card for React and Tailwind, with hover and motion.

Profile Card
OriginalA user profile card with avatar, stats and a follow toggle.

Product Card
OriginalA product card with image, price and add-to-cart feedback.

Pricing Single Card
OriginalA single pricing plan card with feature list and CTA.

Stat Card
OriginalA metric card with value, trend arrow and a small sparkline.

