Pluto UIpluto/ui
Components

Feature Block

An interactive feature showcase component with smooth animations using motion, displaying images that change based on selected features.

// Code for feature-block/basic

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

PropTypeDefaultDescription
itemsFeatureBlockItem[]-Array of feature items to display
classNamestring-Additional CSS classes
showControlsbooleantrueWhether to show navigation buttons

FeatureBlockItem

PropertyTypeRequiredDescription
idstringYesUnique identifier for the feature
titlestringYesFeature title
descriptionstringYesFeature description
iconReactNodeNoIcon component (e.g., from lucide-react)
imagestringYesImage URL for the feature
imageAltstringNoAlt text for the image

Examples

Basic Usage

// Code for feature-block/basic

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:

  1. The openIndex state updates to the clicked feature's index
  2. Motion animates the button opacity and width changes
  3. The description content expands with a smooth height animation using AnimatePresence
  4. The corresponding image fades in with a slide animation
  5. 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 className prop
  • CSS Variables: Uses theme variables for colors (e.g., --muted, --foreground, --border)
  • Motion Props: Customize animations by modifying the motion component 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 motion as 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