Getting Started
Templates
Components
A full-page project showcase component that morphs between a list view and expanded detail view. Features smooth layout animations, hover-triggered preview cards, and support for both images and videos.
Key Features:
import { ProjectTitleMorph } from "@/components/ui/project-title-morph"
const projects = [
{
id: "rebrand",
title: "Brand Redesign",
sectionLabel: "About the Project",
description: [
"A complete visual identity overhaul for a tech startup.",
"We focused on creating a modern, minimal aesthetic.",
],
media: { type: "image", src: "/project-1.jpg", alt: "Brand redesign" },
ctas: [
{ label: "View Live", href: "https://example.com", icon: "external" },
{ label: "Case Study", href: "/case-study", icon: "docs" },
],
},
{
id: "app",
title: "Mobile App",
sectionLabel: "Project Details",
description: ["Cross-platform mobile application built with React Native."],
media: { type: "video", src: "/demo.mp4", poster: "/poster.jpg" },
},
]
export default function Example() {
return (
<ProjectTitleMorph
items={projects}
listLabel="Featured Work"
previewDock="top-right"
/>
)
}| Prop | Type | Default | Description |
|---|---|---|---|
items | ProjectTitleMorphItem[] | required | Array of project items |
defaultActiveId | string | Last item's ID | Initially active project |
listLabel | string | "MY PROJECTS" | Label above the project list |
previewDock | "top-left" | "top-right" | "top-left" | Position of the preview card in list view |
openOnClick | boolean | true | Whether clicking opens detail view |
className | string | undefined | Additional CSS classes |
| Property | Type | Description |
|---|---|---|
id | string | Unique identifier |
title | string | Project title |
sectionLabel | string | Label for the description section |
description | string[] | Array of paragraphs for the description |
media | ProjectPreviewMedia | Optional image or video for preview |
ctas | CTA[] | Optional call-to-action buttons |
type ProjectPreviewMedia =
| { type: "image"; src: string; alt?: string; fit?: "cover" | "contain" }
| { type: "video"; src: string; poster?: string; fit?: "cover" | "contain" }| Property | Type | Description |
|---|---|---|
label | string | Button text |
href | string | Optional link URL |
icon | "external" | "docs" | Optional icon type |
variant | "default" | "secondary" | "outline" | Button variant |
The component respects the user's prefers-reduced-motion setting. When enabled, animations are disabled for a more accessible experience.