Skip to main content

Overview

The TrophyButton is an animated button component that displays a trophy icon. When clicked, it triggers an explosion animation and shows a brief thank you message. This component adds an engaging, gamified element to acknowledge user interaction.

Props

This component does not accept any props. All behavior is self-contained.

Usage

The component can be added to any page where you want to provide a “like” or “appreciation” interaction:
import TrophyButton from "../components/TrophyButton";

<TrophyButton />

Component Structure

src/components/TrophyButton.jsx
import { useState } from "react";
import { Box, IconButton, Typography } from "@mui/material";
import EmojiEventsIcon from "@mui/icons-material/EmojiEvents";

export default function TrophyButton() {
  const [showMessage, setShowMessage] = useState(false);
  const [explode, setExplode] = useState(false);

  const handleClick = () => {
    setExplode(true);
    setShowMessage(true);

    setTimeout(() => setExplode(false), 400);
    setTimeout(() => setShowMessage(false), 2000);
  };

  return (
    <Box sx={{ textAlign: "center" }}>
      <IconButton
        onClick={handleClick}
        sx={{
          bgcolor: "#ffd700",
          color: "#5c4b00",
          width: 60,
          height: 60,
          transition: "all 0.3s ease",
          boxShadow: "0 0 10px rgba(255, 215, 0, 0.5)",
          "&:hover": {
            bgcolor: "#ffea70",
            transform: "scale(1.15)",
            boxShadow: "0 0 20px rgba(255, 215, 0, 0.9)",
          },
          ...(explode && {
            animation: "explode 0.4s ease",
          }),
        }}
      >
        <EmojiEventsIcon sx={{ fontSize: 32 }} />
      </IconButton>

      {showMessage && (
        <Typography
          sx={{
            mt: 1,
            fontSize: 14,
            color: "#ffd700",
            animation: "fadeUp 0.6s ease",
          }}
        >
          ¡Gracias! 🏆
        </Typography>
      )}
    </Box>
  );
}

State Management

useState Hooks

const [showMessage, setShowMessage] = useState(false);
const [explode, setExplode] = useState(false);
  • showMessage: Controls visibility of thank you text
  • explode: Triggers explosion animation

Click Handler

const handleClick = () => {
  setExplode(true);           // Start explosion animation
  setShowMessage(true);       // Show thank you message

  setTimeout(() => setExplode(false), 400);    // End explosion after 400ms
  setTimeout(() => setShowMessage(false), 2000); // Hide message after 2s
};

Animations

Explosion Animation

Scales the button dramatically on click:
@keyframes explode {
  0% { transform: scale(1); }
  50% { transform: scale(1.35); }  /* Grows 35% larger */
  100% { transform: scale(1); }
}
  • Duration: 0.4 seconds
  • Easing: ease
  • Effect: Quick scale up and down

Fade Up Animation

Message appears with upward motion:
@keyframes fadeUp {
  from {
    opacity: 0;
    transform: translateY(10px);  /* Starts 10px below */
  }
  to {
    opacity: 1;
    transform: translateY(0);     /* Ends in final position */
  }
}
  • Duration: 0.6 seconds
  • Easing: ease
  • Effect: Smooth fade in with upward movement

Hover Animation

"&:hover": {
  bgcolor: "#ffea70",           // Lighter gold
  transform: "scale(1.15)",     // Grow 15%
  boxShadow: "0 0 20px rgba(255, 215, 0, 0.9)",  // Stronger glow
}

Styling Details

Button Colors

StateBackgroundText ColorShadow
Default#ffd700 (gold)#5c4b00 (dark brown)10px glow
Hover#ffea70 (light gold)#5c4b0020px glow

Button Size

  • Width: 60px
  • Height: 60px (circular)
  • Icon size: 32px

Message Style

  • Color: #ffd700 (gold)
  • Font size: 14px
  • Margin top: 1 (8px spacing from button)

Material-UI Components

Box

Container for centering:
import { Box } from "@mui/material";
<Box sx={{ textAlign: "center" }}>

IconButton

Rounded button for icon:
import { IconButton } from "@mui/material";

Typography

Message text:
import { Typography } from "@mui/material";

EmojiEventsIcon

Trophy icon:
import EmojiEventsIcon from "@mui/icons-material/EmojiEvents";

Timing Breakdown

0ms    - User clicks button
0ms    - Explosion animation starts
0ms    - Thank you message appears with fadeUp
400ms  - Explosion animation ends
2000ms - Thank you message disappears

Customization Examples

Change Colors

// Blue theme
bgcolor: "#2196F3",
color: "#FFFFFF",
"&:hover": {
  bgcolor: "#42A5F5",
}

Change Icon

import StarIcon from "@mui/icons-material/Star";
import FavoriteIcon from "@mui/icons-material/Favorite";
import ThumbUpIcon from "@mui/icons-material/ThumbUp";

<IconButton>
  <StarIcon sx={{ fontSize: 32 }} />
</IconButton>

Change Message

{showMessage && (
  <Typography sx={{ ... }}>
    Thank you! ⭐
  </Typography>
)}

Longer Display Time

setTimeout(() => setShowMessage(false), 4000);  // 4 seconds instead of 2

Faster Animation

setTimeout(() => setExplode(false), 250);  // Quicker explosion

Use Cases

Appreciation Button

Add to project pages to let users show appreciation:
<Box sx={{ textAlign: "center", mt: 4 }}>
  <Typography variant="h6" gutterBottom>
    Did you like this project?
  </Typography>
  <TrophyButton />
</Box>

Achievement Unlock

Celebrate user milestones:
{userCompletedProject && <TrophyButton />}

Interactive Tutorial

Reward users for completing steps:
<Steps>
  <Step title="Complete setup">
    Instructions here...
    <TrophyButton />
  </Step>
</Steps>

Accessibility

The IconButton component automatically includes proper ARIA attributes and keyboard support.

Keyboard Support

  • Tab: Focus the button
  • Enter/Space: Trigger click animation

Screen Readers

Add an aria-label for context:
<IconButton
  onClick={handleClick}
  aria-label="Award trophy"
  sx={{ ... }}
>

Performance

CSS animations are hardware-accelerated for smooth performance:
  • transform - GPU accelerated ✅
  • opacity - GPU accelerated ✅
No JavaScript animation loops = excellent performance.

Browser Compatibility

All animations use standard CSS keyframes supported in:
  • Chrome ✓
  • Firefox ✓
  • Safari ✓
  • Edge ✓
  • Opera ✓

Best Practices

Use sparingly - too many animated elements can feel overwhelming. One interactive button per view is usually sufficient.
The gold color (#ffd700) evokes achievement and success, making it perfect for appreciation or award interactions.
Consider users with motion sensitivity. Add a prefers-reduced-motion media query to disable animations if needed:
@media (prefers-reduced-motion: reduce) {
  .trophy-button {
    animation: none !important;
  }
}

BotonFlotante

Another interactive button with animations

FlipScienceCard

Interactive card with hover effects

Build docs developers (and LLMs) love