KQ-1271 · PROFILE/LIFT

Profile Lift

A profile card whose portrait steps out of its frame: hovering it or moving keyboard focus into it lifts the portrait out of a recessed circular well on the snap spring, growing past the frame's edge while its shadow falls into the empty ring below and softens with the height, as the figures count up from zero and the follow pill docks on the frame's rim on snap; a mouse or pen tilts the card toward itself on glide, the lifted portrait shifting further than the card. Pressing the card grows it into a sheet with the bio, links and followers in common, one shared-layout surface on the glide spring with the portrait, name and figures travelling to their places, and Escape or the close button folds it back the same way. The card and the follow pill are real buttons that Enter and Space press, focus moves to the sheet's close button and back to the card, and under reduced motion nothing tilts or travels: the frame lights, the shadow and pill fade in place and the sheet cross-fades.

KQ-1271 · PROFILE/LIFT

Ines Calder

Product designer at Fernworks

Followers
2,418
Following
312
Projects
46

Followed by Tomas and 11 others

not following · 2,418 followers · sheet closed

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/profile-lift

Props

name
string
default "Ines Calder"
The person: the card's heading, the drawn portrait's seed and every accessible name.
handle
string
default "@ines.calder"
Shown in the open sheet above the bio.
role
string
default "Product designer at Fernworks"
The line under the name.
portrait
React.ReactNode
default —
What fills the portrait disc, such as an img. Defaults to a head-and-shoulders portrait drawn from the name in the accent's hue.
bio
string
default —
The open sheet's paragraph.
figures
ProfileFigure[]
default defaultProfileFigures
The counted row ({ id, label, value }). The first figure is the followers count, which following adds one to.
links
ProfileLink[]
default defaultProfileLinks
The open sheet's links ({ id, label, detail?, href }).
mutuals
{ names: string[]; total: number }
default defaultProfileMutuals
Followers in common: the named ones shown first, then the rest as a count.
following / defaultFollowing
boolean
default false
Whether the viewer follows this person, controlled or initial.
onFollowingChange
(following: boolean) => void
default —
Fires from the press that changed it, with the new state.
expanded / defaultExpanded
boolean
default false
Whether the card is open as the full sheet, controlled or initial.
onExpandedChange
(expanded: boolean) => void
default —
Fires from the press or the Escape that opened or closed the sheet.
followLabel
string
default "Follow"
The follow button before following; also the start of its accessible name.
followingLabel
string
default "Following"
The follow button once following. The pill is always as wide as the longer label.
lift
number
default 0.6
How far the portrait steps out of its frame, 0 to 1: how high it rises, how much it grows and how deep its shadow falls.
tilt
number
default 6
How far the card turns toward the pointer, in degrees on each axis (up to 10); 0 holds it flat.
stats
"count" | "still" | "off"
default "count"
What the figures do as the portrait lifts: count up from zero, stay still, or leave the card.
countDuration
number
default 700
How long the count-up runs, in ms.
formatFigure
(value: number) => string
default —
How a figure is written. Defaults to compact en-US, "2.4K".
size
"sm" | "md" | "lg"
default "md"
The portrait: 72, 88 or 104 px across, in a frame 20 to 28 px wider.
accent
string
default "var(--accent)"
The follow button's fill and the drawn portrait's hue, any CSS colour.
sound
boolean
default false
Play a swish as the visitor opens or closes the sheet and a pop as they follow or unfollow. Nothing sounds on hover.
disabled
boolean
default false
Nothing lifts, tilts or opens, and the card is drawn at reduced strength.
className
string
default —
Classes for the card's outer box.