Skip to content

Instantly share code, notes, and snippets.

@AlexIsMaking
Last active January 3, 2024 09:06
Show Gist options
  • Save AlexIsMaking/26f3893847b9f2ec297885c49428ef8e to your computer and use it in GitHub Desktop.
Save AlexIsMaking/26f3893847b9f2ec297885c49428ef8e to your computer and use it in GitHub Desktop.
Glowy Border Shimmer Button React component with Tailwind CSS styling. Based on @jh3yy's button - https://codepen.io/jh3y/pen/vYbyKeL
import { useEffect } from "react";
const config = {
text: "Submit",
hue: 180,
alpha: 1,
window: 1.4,
speed: 1,
blur: 10,
spread: 120,
thickness: 2,
};
export default function ButtonWithGlow() {
useEffect(() => {
// Set initial radius based on current screen size
const initialRadius = window.matchMedia("(min-width: 640px)").matches ? 32 : 13;
config.radius = initialRadius;
// Listen for screen size changes to update the radius
const handleResize = () => {
config.radius = window.matchMedia("(min-width: 640px)").matches ? 32 : 13;
document.documentElement.style.setProperty("--radius", config.radius);
};
window.addEventListener("resize", handleResize);
// Set initial properties
Object.keys(config).forEach((key) => {
document.documentElement.style.setProperty(`--${key}`, config[key]);
});
document.body.dataset.showGlows = config.constant;
// Clean up
return () => window.removeEventListener("resize", handleResize);
}, []);
return (
<div className="scene grid place-items-center min-h-screen overflow-hidden bg-black">
<button className="glow-button text-md sm:text-4xl p-2 sm:p-8 px-6 sm:px-14 grid border-0 place-items-center whitespace-nowrap relative shadow-[custom] transition-[box-shadow, scale, background] scale-[custom]">
<span className="glows">
<span className="spark__container spark__glows">
<span className="spark" />
<span className="spark" />
</span>
</span>
<span className="spark__container">
<span className="spark" />
<span className="spark" />
</span>
<span className="spark__container spark__container--reveal">
<span className="spark" />
<span className="spark" />
</span>
<span className="backdrop" />
<span className="text bg-gradient-to-r from-[#custom] to-[#custom] bg-[position] bg-clip-text text-transparent transition-[background-position]">
{config.text}
</span>
<span className="labels">
<span className="label label--button">Button</span>
<span className="label label--glow">Glows</span>
<span className="label label--text">Text</span>
</span>
</button>
</div>
);
}
*,
*:after,
*:before {
box-sizing: border-box;
}
:root {
--saturation: 20%;
--transition: 0.15s;
--glow: hsl(var(--hue, 150) 80% 70% / var(--alpha, 1));
--border-radius: calc(var(--radius) * 1px);
--border-width: calc(var(--thickness) * 1px);
--active: 0;
--glow-spread: calc(var(--spread) * 1deg);
}
.glow-button {
--bg: radial-gradient(40% 50% at center 100%, hsl(var(--hue) var(--saturation) 72% / 0.15), transparent),
radial-gradient(80% 100% at center 120%, hsl(var(--hue) var(--saturation) 70% / 0.2), transparent), hsl(260 0% 2%);
background: var(--bg);
place-items: center;
border-radius: var(--border-radius);
box-shadow: 0 0.025em 0.4em -0.02em hsl(0 0% 100% / 0.25), 0 0.05em 0 0 hsl(260 0% 50%) inset,
0 -0.05em 0 0 hsl(260 0% 0%) inset;
transition: box-shadow var(--transition), scale var(--transition), background var(--transition);
scale: calc(1 + (var(--active) * 0.025));
}
/* Feint border */
.glow-button::before {
--saturation: 90%;
content: "";
position: absolute;
inset: 0;
border: 1px solid hsl(var(--hue) var(--saturation) 80% / 0.3);
border-radius: var(--border-radius);
pointer-events: none;
}
.glow-button:active {
scale: 1;
}
.spark:before {
content: "";
position: absolute;
}
/* Purely to decorate the use of CQ elements sliding along */
.spark:after {
/* background: red;*/
content: "";
position: absolute;
inset: 0;
z-index: -1;
}
/* Optional backdrop – For some reason, if you go with the mask-composite, you lose the glow... */
.backdrop {
position: absolute;
inset: 0;
background: linear-gradient(transparent 5%, hsl(0 0% 0% / 0.5), transparent) padding-box,
radial-gradient(40% 50% at center 100%, hsl(var(--hue) var(--saturation) 72% / 0.15), transparent) padding-box,
radial-gradient(80% 100% at center 120%, hsl(var(--hue) var(--saturation) 70% / 0.2), transparent) padding-box,
linear-gradient(hsl(var(--hue) var(--saturation) 5%), hsl(var(--hue) var(--saturation) 4%)) padding-box;
border: var(--border-width) solid transparent;
border-radius: var(--border-radius);
transition: background var(--transition) opacity var(--transition);
/* opacity: 0;*/
}
.glow-button:is(:hover, :focus-visible) {
--active: 1;
outline: none;
}
.text {
translate: 0 0;
letter-spacing: 0.01ch;
background: linear-gradient(
95deg,
hsl(0 0% 90%) 15%,
hsl(0 0% 50% / 1),
hsl(0 0% 100% / 0.2),
hsl(0 0% 80%),
hsl(0 0% 90%) 85%
);
background-size: 500% 100%;
background-position: 0 0;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
transition: background-position calc(var(--transition) * 6);
}
.glow-button:is(:hover, :focus-visible) .text {
animation: shimmer 1s both;
}
@keyframes shimmer {
0% {
background-position: 100% 0;
}
}
.glow-button .spark__container {
position: absolute;
inset: 0px;
/* With a backdrop */
overflow: hidden;
/* Without a backdrop */
/*mask: linear-gradient(transparent, transparent), linear-gradient(white, white);
mask-clip: padding-box, border-box;
mask-composite: intersect;
border: var(--border-width) solid transparent;*/
}
.glows {
filter: blur(calc(var(--blur) * 1px));
container-type: size;
position: absolute;
inset: 0;
}
.glow-button > .spark__container {
container-type: size;
}
.glow-button .spark:nth-of-type(2) {
rotate: 180deg;
animation-direction: alternate-reverse;
}
.glow-button .spark {
position: absolute;
left: 0;
top: 0;
height: 100%;
aspect-ratio: 1;
border-radius: 0;
overflow: visible;
mask: none;
animation: slide calc(var(--speed) * 1s) ease-in-out infinite alternate;
animation-play-state: paused;
}
.glow-button:hover .spark {
animation-play-state: running;
}
.glow-button .spark:before {
inset: -100%;
background: conic-gradient(
from calc(270deg - (var(--glow-spread) * 0.5)),
var(--glow) 0,
var(--glow) var(--glow-spread),
transparent var(--glow-spread)
);
translate: 0 0;
transform: rotate(0deg);
width: auto;
animation: spin calc(var(--speed) * 2s) infinite linear;
animation-play-state: paused;
}
.glow-button:is(:hover, :focus-visible) .spark:before {
animation-play-state: running;
}
@keyframes spin {
0% {
rotate: 0deg;
}
15%,
35% {
rotate: 90deg;
}
65%,
85% {
rotate: 270deg;
}
100% {
rotate: 360deg;
}
}
@keyframes slide {
to {
translate: calc(100cqw - 100%) 0;
}
}
/* Overrides */
.glow-button .spark {
background: transparent;
}
.glow-button .spark__container {
border-radius: var(--border-radius);
opacity: 0;
}
.spark {
transition: opacity var(--transition);
opacity: 0;
}
.glow-button:is(:hover, :focus-visible) .spark {
opacity: 1;
}
.glow-button:is(:hover, :focus-visible) .spark__container:not(.spark__container--reveal) {
animation: reveal calc(var(--window) * 1s) both;
}
@keyframes reveal {
0%,
100% {
opacity: 0;
}
20%,
80% {
opacity: 1;
}
}
[data-show-glows="true"] .spark,
[data-show-glows="true"] .spark__container:not(.spark__container--reveal) {
opacity: 1;
}
[data-show-glows="true"] .glow-button .spark::before,
[data-show-glows="true"] .glow-button .spark {
animation-play-state: running;
}
[data-show-glows="true"] .glow-button:is(:hover, :focus-visible) .spark__container {
animation: none;
}
.label {
position: absolute;
left: calc(100% + 6rem);
translate: 0 -50%;
top: 50%;
color: hsl(0 0% 80%);
opacity: 0;
}
.spark__container--reveal .spark::after {
/* background: red;*/
opacity: 0.65;
border: 4px dashed hsl(0 0% 80%);
}
.labels {
position: absolute;
inset: 0;
}
.label--glow {
transform: translate3d(0, 0, 100px);
}
.label--text {
transform: translate3d(0, 0, 200px);
}
.measurements {
position: absolute;
inset: 0;
color: hsl(0 0% 50%);
opacity: 0;
pointer-events: none;
}
.width {
position: absolute;
left: 50%;
top: 100%;
translate: -50% 100%;
}
.height {
position: absolute;
right: 100%;
top: 50%;
translate: 0% -50%;
rotate: 90deg;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment