CREATIVE GLOW BUTTON HOVER EFFECT

HOW TO MAKE YOUR WEBSITE DESIGN MORE APPEALING?

Read the article to the end to find a link to our Codepen — we've shared the source code for our custom glow button made with React.js, TypeScript/JavaScript, HTML and CSS/Scss.


At Overcode, we believe in paying attention to details, both in coding and product design.
In today's competitive corporate website landscape, unique design elements can help your website stand out from the rest. This is particularly crucial for companies aiming to establish a strong brand and a recognizable corporate style.


→ USER EXPERIENCE

Unusual and rare interface details contribute to enhancing the user experience. When users visit a corporate website, they seek not only information but also a well-designed and easily navigable interface that incorporates unexpected animations, interesting transition effects, or interactive buttons, making the User Experience (UX) more memorable.

To assist our colleagues in creating adorable UI interfaces, we share our code and ideas through a link on Codepen or detailed Reels on our Instagram profile.

→ FULL CODE

Button.tsx

const { useEffect, useMemo, useRef, useState } = React;

type Props = {
  children: ReactNode;
  onClick?: MouseEventHandler<HTMLButtonElement>;
};

const GlowButton: FC<Props> = ({ children, onClick }) => {
  const [offsetWidth, setOffsetWidth] = useState<number>(0);
  const [offsetHeight, setOffsetHeight] = useState<number>(0);

  const [translateX, setTranslateX] = useState<string>("-40%");
  const [translateY, setTranslateY] = useState<string>("-30%");

  const buttonRef = useRef<HTMLButtonElement>(null);

  // This function calculate button's position
  const getPosition = () => {
    if (buttonRef.current) {
      setOffsetWidth(buttonRef.current.offsetWidth);
      setOffsetHeight(buttonRef.current.offsetHeight);
    }
  };

  useEffect(() => {
    getPosition();
  }, []);

  const onMove = (e: MouseEvent) => {
    if (buttonRef.current) {
      const { pageX, pageY } = e;

      const rect = buttonRef.current.getBoundingClientRect();

      setTranslateX(
        `${pageX - rect.left - window.scrollX - offsetWidth / 2}px`
      );
      setTranslateY(
        `${pageY - rect.top - window.scrollY - offsetHeight / 2}px`
      );
    }
  };

  const styleValue = useMemo(
    () => ({
      transform: `translate(${translateX}, ${translateY})`
    }),
    [translateX, translateY]
  );

  return (
    <button
      className="glow-button"
      onClick={onClick}
      onPointerMove={onMove}
      ref={buttonRef}
    >
      {children}
      <div className="glow-button__glow">
        <div className="glow-button__glow-light" style={styleValue} />
      </div>

      <div className="glow-button__border">
        <div className="glow-button__border-light" style={styleValue} />
      </div>
    </button>
  );
};

ReactDOM.render(
  <GlowButton>Overcode</GlowButton>,
  document.getElementById("root")
);

button.scss

:root {
  --purple-1: #ead9ef;
  --purple-2: #0d0915;
}

body {
  height: 100vh;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--purple-2);
}

@mixin button {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  padding: 14px 30px;
  height: 50px;
  font-size: 14px;
  border-radius: 25px;
  cursor: pointer;
  outline: none;
  white-space: nowrap;
  user-select: none;
  appearance: none;
}

.glow-button {
  --bg-color: var(--purple-2);
  --text-color: var(--purple-1);

  @include button;

  background: var(--bg-color);
  color: var(--text-color);
  margin: 1px;
  position: relative;
  border: none;
  transition: all 0.15s ease;

  &__border {
    position: absolute;
    border-radius: 1000px;
    top: -2px;
    bottom: -2px;
    right: -2px;
    left: -2px;
    z-index: -1;
    background: #3b039b;
    overflow: hidden;

    &-light {
      background: #590285;
      z-index: 2;
      filter: blur(15px);
    }
  }

  &__glow {
    position: absolute;
    background: #9d00c5;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    z-index: -10;
    overflow: hidden;
    opacity: 0.4;
    transition: opacity 0.5s ease;

    filter: blur(15px);
    -webkit-filter: blur(15px);

    -webkit-backface-visibility: hidden;
    -moz-backface-visibility: hidden;
    -webkit-transform: translate3d(0, 0, 0);
    -moz-transform: translate3d(0, 0, 0);

    &-light {
      background: #3b039b;
      z-index: 3;
      opacity: 0;
    }
  }

  .glow-button__border-light,
  .glow-button__glow-light {
    position: absolute;
    width: 100%;
    height: 100%;
    transition: opacity 0.5s ease;
  }

  &:hover {
    .glow-button__glow {
      opacity: 1;
    }

    .glow-button__glow-light {
      opacity: 1;
    }
  }
}