Ripple Button
A Button with an animated ripple effect styled with Tailwind CSS.
Example#
import {Button} from 'react-aria-components';
import {useEffect, useRef, useState} from 'react';
import Airplane from '@spectrum-icons/workflow/Airplane';
function RippleButton(props) {
  const [coords, setCoords] = useState(null);
  let timeout = useRef<ReturnType<typeof setTimeout> | null>(null);
  let onPress = (e) => {
    setCoords({ x: e.x, y: e.y });
    if (e.x !== -1 && e.y !== -1) {
      clearTimeout(timeout.current);
      timeout.current = setTimeout(() => setCoords(null), 600);
    }
  };
  useEffect(() => {
    return () => {
      clearTimeout(timeout.current);
    };
  }, []);
  return (
    <div className="bg-linear-to-r from-teal-300 to-cyan-500 p-12 rounded-lg flex justify-center">
      <Button
        onPress={onPress}
        className={`
      relative overflow-hidden
      inline-flex items-center justify-center rounded-md bg-black/50 bg-clip-padding border border-white/20 px-6 py-4 text-white text-lg
      hover:bg-black/60 pressed:bg-black/70 transition-colors cursor-default outline-hidden focus-visible:ring-2 focus-visible:ring-white/75`}
      >
        {coords && (
          <div
            key={`,`}
            className="absolute h-8 w-8 rounded-full opacity-100 bg-white/60"
            style={{
              animation: 'ripple 600ms linear',
              left: coords.x - 15,
              top: coords.y - 15
            }}
          />
        )}
        <span className="flex items-center gap-4">{props.children}</span>
      </Button>
    </div>
  );
}
<RippleButton>
  <Airplane size="S" /> Book flight
</RippleButton>import {Button} from 'react-aria-components';
import {useEffect, useRef, useState} from 'react';
import Airplane from '@spectrum-icons/workflow/Airplane';
function RippleButton(props) {
  const [coords, setCoords] = useState(null);
  let timeout = useRef<
    ReturnType<typeof setTimeout> | null
  >(null);
  let onPress = (e) => {
    setCoords({ x: e.x, y: e.y });
    if (e.x !== -1 && e.y !== -1) {
      clearTimeout(timeout.current);
      timeout.current = setTimeout(
        () => setCoords(null),
        600
      );
    }
  };
  useEffect(() => {
    return () => {
      clearTimeout(timeout.current);
    };
  }, []);
  return (
    <div className="bg-linear-to-r from-teal-300 to-cyan-500 p-12 rounded-lg flex justify-center">
      <Button
        onPress={onPress}
        className={`
      relative overflow-hidden
      inline-flex items-center justify-center rounded-md bg-black/50 bg-clip-padding border border-white/20 px-6 py-4 text-white text-lg
      hover:bg-black/60 pressed:bg-black/70 transition-colors cursor-default outline-hidden focus-visible:ring-2 focus-visible:ring-white/75`}
      >
        {coords && (
          <div
            key={`,`}
            className="absolute h-8 w-8 rounded-full opacity-100 bg-white/60"
            style={{
              animation: 'ripple 600ms linear',
              left: coords.x - 15,
              top: coords.y - 15
            }}
          />
        )}
        <span className="flex items-center gap-4">
          {props.children}
        </span>
      </Button>
    </div>
  );
}
<RippleButton>
  <Airplane size="S" /> Book flight
</RippleButton>import {Button} from 'react-aria-components';
import {
  useEffect,
  useRef,
  useState
} from 'react';
import Airplane from '@spectrum-icons/workflow/Airplane';
function RippleButton(
  props
) {
  const [
    coords,
    setCoords
  ] = useState(null);
  let timeout = useRef<
    ReturnType<
      typeof setTimeout
    > | null
  >(null);
  let onPress = (e) => {
    setCoords({
      x: e.x,
      y: e.y
    });
    if (
      e.x !== -1 &&
      e.y !== -1
    ) {
      clearTimeout(
        timeout.current
      );
      timeout.current =
        setTimeout(
          () =>
            setCoords(
              null
            ),
          600
        );
    }
  };
  useEffect(() => {
    return () => {
      clearTimeout(
        timeout.current
      );
    };
  }, []);
  return (
    <div className="bg-linear-to-r from-teal-300 to-cyan-500 p-12 rounded-lg flex justify-center">
      <Button
        onPress={onPress}
        className={`
      relative overflow-hidden
      inline-flex items-center justify-center rounded-md bg-black/50 bg-clip-padding border border-white/20 px-6 py-4 text-white text-lg
      hover:bg-black/60 pressed:bg-black/70 transition-colors cursor-default outline-hidden focus-visible:ring-2 focus-visible:ring-white/75`}
      >
        {coords && (
          <div
            key={`,`}
            className="absolute h-8 w-8 rounded-full opacity-100 bg-white/60"
            style={{
              animation:
                'ripple 600ms linear',
              left:
                coords
                  .x -
                15,
              top:
                coords
                  .y - 15
            }}
          />
        )}
        <span className="flex items-center gap-4">
          {props
            .children}
        </span>
      </Button>
    </div>
  );
}
<RippleButton>
  <Airplane size="S" />
  {' '}
  Book flight
</RippleButton>@keyframes ripple {
  from {
    transform: scale(0);
    opacity: 1;
  }
  to {
    transform: scale(6);
    opacity: 0;
  }
}@keyframes ripple {
  from {
    transform: scale(0);
    opacity: 1;
  }
  to {
    transform: scale(6);
    opacity: 0;
  }
}@keyframes ripple {
  from {
    transform: scale(0);
    opacity: 1;
  }
  to {
    transform: scale(6);
    opacity: 0;
  }
}Tailwind config#
This example uses the tailwindcss-react-aria-components plugin. When using Tailwind v4, add it to your CSS:
@import "tailwindcss";
@plugin "tailwindcss-react-aria-components";@import "tailwindcss";
@plugin "tailwindcss-react-aria-components";@import "tailwindcss";
@plugin "tailwindcss-react-aria-components";Tailwind v3
When using Tailwind v3, add the plugin to your tailwind.config.js instead:
module.exports = {
  // ...
  plugins: [
    require('tailwindcss-react-aria-components')
  ]
};module.exports = {
  // ...
  plugins: [
    require('tailwindcss-react-aria-components')
  ]
};module.exports = {
  // ...
  plugins: [
    require(
      'tailwindcss-react-aria-components'
    )
  ]
};
Note: When using Tailwind v3, install tailwindcss-react-aria-components version 1.x instead of 2.x.
Components#
Button
A button allows a user to perform an action.