Organic Growth
Wrap any element and vines, leaves and flowers grow out of its edges on hover or focus.
Read how it's builtPreview
Suggest a component
Setup
Install with the shadcn CLI
One command adds every file, the npm packages and any Kinetik components it builds on. Needs a components.json; the CLI offers to create one if your project has none.
Or install manually
- 1
Create a
components/ui/organic-growth/folder and copy every file from the Code tab into it. Each file does one job, so you can read or change a piece without the rest. - 2
Import and render:
Exampleimport OrganicGrowth from "@/components/ui/organic-growth" <OrganicGrowth padding={70}> <div className="rounded-2xl border p-6">Hover me</div> </OrganicGrowth>
Usage
Hover the card or focus a field and the plant grows; leave and it retracts.
Pass active to keep it grown, for example after a form is sent.
import OrganicGrowth from "@/components/ui/organic-growth"
export function Card() {
return (
<OrganicGrowth padding={70}>
<div className="rounded-2xl border p-6">Hover me</div>
</OrganicGrowth>
)
}
Each vine is described by a Sprout: which edge it grows from, where along that
edge, which way it bends, how long it is, and how it ends.
const sprouts: Sprout[] = [
{ edge: "top", t: 0.2, side: -1, length: 60, end: "curl" },
{ edge: "right", t: 0.5, side: 1, length: 80, end: "bloom", blooms: [0.5] },
]
The plant is built from a seeded random generator, so the same seed always
gives the same arrangement. Colours read --og-* CSS variables, or pass a
palette to override them.
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
active | boolean | — | Force grown or retracted; ignores hover and focus while set. |
trigger | "hover" | "focus" | "hover-focus" | "manual" | "hover-focus" | What grows the vines when active is unset. |
sprouts | Sprout[] | 14 vines | Where vines grow, see Usage. |
seed | number | 2 | Change it for a different arrangement. |
padding | number | 1 | Room (px) around the element for vines to grow into. |
tuck | number | 18 | How far (px) vines start hidden under the edge. |
speed | number | 0.8 | Above 1 grows faster, below 1 slower. |
stagger | number | 0.01 | Delay (s) between sprouts starting. |
palette | Partial<GrowthPalette> | — | Stem, leaf, petal and pollen colours, plus flowerScale. |
onGrowChange | (grown: boolean) => void | — | Fires whenever the plant grows or retracts. |
Accessibility
- The plant is a decorative
aria-hiddenSVG behind your content, which stays fully interactive - With
prefers-reduced-motion, vines fade in instead of growing - On touch screens, tapping the element grows it and tapping elsewhere retracts it
Further reading
How I Built OrganicGrowth,
a 7-minute walkthrough of the recipe behind the vines: Bézier stems,
stroke-dashoffset timing for the leaves, and the seeded random generator that
keeps every plant repeatable.