Components
Feature Block
An interactive feature showcase component with smooth animations using motion, displaying images that change based on selected features.
Installation
Loading installation instructions...
Usage
import { FeatureBlock } from "@/components/pluto-ui/feature-block"import { FeatureBlock, type FeatureBlockItem } from "@/components/pluto-ui/feature-block"
import { Smartphone, Camera } from "lucide-react"
const features: FeatureBlockItem[] = [
{
id: "1",
title: "Modern Design",
description: "Experience sleek and modern smartphone design with premium materials and attention to detail.",
icon: <Smartphone className="w-5 h-5" />,
image: "https://example.com/image1.jpg",
imageAlt: "Modern smartphone design",
},
{
id: "2",
title: "Advanced Camera",
description: "Capture stunning photos with our advanced camera system featuring multiple lenses and AI enhancement.",
icon: <Camera className="w-5 h-5" />,
image: "https://example.com/image2.jpg",
imageAlt: "Smartphone camera closeup",
},
]
<FeatureBlock items={features} />Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | FeatureBlockItem[] | - | Array of feature items to display |
className | string | - | Additional CSS classes |
showControls | boolean | true | Whether to show navigation buttons |
FeatureBlockItem
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier for the feature |
title | string | Yes | Feature title |
description | string | Yes | Feature description |
icon | ReactNode | No | Icon component (e.g., from lucide-react) |
image | string | Yes | Image URL for the feature |
imageAlt | string | No | Alt text for the image |
Examples
Basic Usage
Features
- Smooth Animations: Powered by motion for fluid transitions and animations
- Simple State Management: Uses React state for clean, predictable behavior
- Image Transitions: Smooth slide and fade animations when switching between features
- Expandable Content: Animated height transitions for feature descriptions
- Navigation Controls: Optional next/previous buttons for easy navigation
- Fully Customizable: Easy to customize with Tailwind classes and motion props
- Theme-aware: Fully supports light and dark themes using CSS variables
- No CSS File Required: All styling handled with Tailwind and inline styles
How It Works
The component uses React state (useState) to track which feature is currently open. When a feature is clicked:
- The
openIndexstate updates to the clicked feature's index - Motion animates the button opacity and width changes
- The description content expands with a smooth height animation using
AnimatePresence - The corresponding image fades in with a slide animation
- Previous images fade out smoothly
The component uses AnimatePresence with mode="wait" for image transitions to ensure smooth crossfades between images.
Animation Details
- Button Animations: Fade out when opening, with width transitions for smooth expansion
- Content Animations: Height animates from 0 to auto with opacity fade-in
- Image Animations: Slide in from right (15%) with opacity transitions
- Control Buttons: Fade in/out with translate animations when features are opened/closed
- Hover Effects: Subtle background and shadow changes on hover
Styling
The component uses Tailwind CSS for all styling and can be customized through:
- Tailwind Classes: Pass custom classes via the
classNameprop - CSS Variables: Uses theme variables for colors (e.g.,
--muted,--foreground,--border) - Motion Props: Customize animations by modifying the
motioncomponent props - Responsive Design: Uses
clamp()for fluid typography and spacing
Customization
Custom Animations
You can customize animations by modifying the motion props:
<motion.div
animate={{ opacity: 1 }}
transition={{ duration: 0.5, ease: "easeInOut" }}
>
{/* content */}
</motion.div>Custom Styling
Override styles using Tailwind classes:
<FeatureBlock
items={features}
className="custom-class"
/>Notes
- Requires
motionas a dependency - The first image is always visible when no features are open
- Navigation buttons only appear when a feature is open
- Images use lazy loading (except the first one) for better performance
- The component uses container queries (
containerType: "inline-size") for responsive sizing
