Blog

2025-08-20·react

Creating a Pressable Button with Depress Effect in Nextjs/React

Taher Hathi

Taher Hathi avatar

Taher Hathi

Learn how to build an interactive button that simulates a physical press by depressing its middle layer, using React and Framer Motion for smooth animations.

Cover image

Creating interactive buttons that mimic real-world physical interactions can greatly enhance user experience in web applications. A pressable button with a depress effect, where the middle layer sinks in on click, provides tactile feedback and makes interfaces feel more engaging. This article guides you through building such a button step by step using React and Framer Motion.

The Challenge with Standard Buttons

Traditional buttons in web apps often lack depth and responsiveness. They might change color or scale slightly on hover or click, but they don't simulate the physical "press" of a real button. This can make interfaces feel flat, especially in games, dashboards, or interactive UIs where feedback is key. Common issues include:

  • Lack of visual depth, making buttons feel static
  • Inadequate feedback on press, leading to uncertainty if the click registered
  • Poor accessibility for touch devices without smooth gestures
  • Inconsistent behavior across mouse and touch inputs

Building the Adaptive Solution

Our approach creates a layered button using images (or SVGs) for bottom, middle, and top layers. The middle layer will animate downward on press, creating a depress effect. We'll use React for state management and Framer Motion for spring-based animations to make it feel natural.

Key Features

The pressable button includes several design considerations:

Press and Release Mechanics

  • Depresses on mouse down or touch start for immediate feedback
  • Returns to original position on release with a bouncy spring animation
  • Stays pressed during hold for sustained interaction
  • Handles both mouse and touch events seamlessly

Visual and Animation Details

  • Layered structure with static bottom and top, movable middle
  • Smooth translation and scaling for a realistic sink-in effect
  • Customizable depress depth (e.g., 24px) and scale (e.g., 0.98)
  • Transition effects that feel responsive and fun

Consistent Behavior Across Devices

  • Works on desktop with mouse and mobile with touch
  • Accessible with ARIA labels and proper event handling
  • Supports light and dark modes via class names
  • Efficient performance with minimal DOM updates

Implementation Details

The button uses a custom state to track press status and Framer Motion's motion component for the middle layer. Here's the step-by-step breakdown:

Step 1: Set Up Your React Project

Start with a basic React app. If using Create React App:

1npx create-react-app pressable-button-app
2cd pressable-button-app

Install Framer Motion:

1npm install framer-motion

Step 2: Prepare Button Assets

You'll need three SVG images: bottom (base), middle (pressable part), and top (overlay). For this example, use placeholders from a public source or create simple ones. Here's an example using URLs from the original design:

  • Bottom: https://nextjsshop.com/button/bottom.svg
  • Middle: https://nextjsshop.com/button/middle1.svg
  • Top: https://nextjsshop.com/button/top.svg

Place them in your public folder or use remote URLs.

Step 3: Create the Button Component

In src/components/PressableButton.tsx, set up the basic structure with state for press tracking.

1import React, { useState } from "react";
2import { motion } from "framer-motion";

Add hooks for press state and event handlers.

Step 4: Handle Press Events

Use onMouseDown, onMouseUp, onTouchStart, and onTouchEnd to manage the press state.

Step 5: Animate the Middle Layer

Wrap the middle image in motion.img and animate its y (translateY) and scale based on the press state. Use a spring transition for smoothness.

Step 6: Style the Layers

Position layers absolutely, with z-indices to stack them correctly. Set a fixed width (e.g., 320px) for the button.

Accessibility Considerations

Ensure the button is accessible:

  • Use a <button> element for semantics
  • Add aria-label for screen readers
  • Maintain focus styles and keyboard support
  • High contrast for visibility in different modes
  • Test with tools like Lighthouse for ARIA compliance

Complete Implementation Code

Here's the full code for the pressable button component:

1"use client";
2
3import React, { useState } from "react";
4import { motion } from "framer-motion";
5
6const PressableButton = () => {
7  const [isPressed, setIsPressed] = useState(false);
8
9  const handlePressStart = () => {
10    setIsPressed(true);

Note: Adjust z-indices as needed (z-10, z-20, z-30) to ensure proper layering.

Integration and Usage

Integrate the button into your app like this:

1import PressableButton from "./components/PressableButton";
2
3function App() {
4  return (
5    <div className="flex justify-center items-center h-screen">
6      <PressableButton />
7    </div>
8  );
9}
10

Live Example

Performance and Bundle Considerations

This implementation is lightweight:

  • Framer Motion adds minimal overhead for animations
  • No unnecessary re-renders thanks to React state management
  • Image layers load efficiently with lazy loading if needed
  • Works well on low-end devices with optimized springs

Customization Options

Customize easily:

Animation Tweaks

  • Change stiffness and damping for different bounce feels
  • Adjust y: 24 to deeper or shallower depress
  • Add rotation or other transforms for unique effects

Styling Flexibility

  • Replace images with CSS shapes for non-image versions
  • Add hover effects via CSS classes
  • Integrate with Tailwind or other frameworks
  • Support themes by swapping image sources

Best Practices and Recommendations

Follow these for optimal results:

User Testing

  • Test on real devices for touch feedback
  • Gather feedback on press depth and speed
  • Ensure it doesn't interfere with rapid clicks

Optimization

  • Use WebP or optimized SVGs for images
  • Memoize components if used in lists
  • Profile animations for 60fps performance

Edge Cases

  • Handle long presses or drags
  • Support disabled states
  • Integrate with form submissions or navigation

Conclusion

Building a pressable button with a depress effect elevates your UI from basic to immersive. By leveraging React's state and Framer Motion's animations, you create components that delight users across devices. This step-by-step guide provides a solid foundation—experiment and adapt it to your projects for truly interactive experiences.

Share this post

Creating a Pressable Button with Depress Effect in Nextjs/React | Nextjsshop Blog