Skip to content

Glare Hover

A diagonal light glare on hover using a ::before gradient, CSS variables, and background-position animation—no extra global keyframes required.

Pro

Popular

For teams that need more.

$49/mo
Unlimited projects
Team collaboration
Advanced analytics
SSO (coming soon)

Installation

Copy and paste the following code into your project:

vue
<script setup lang="ts">
import { computed } from "vue";
import { cn } from "@/lib/utils";

interface GlareHoverProps {
  class?: string;
  width?: string;
  height?: string;
  background?: string;
  color?: string;
  opacity?: number;
  angle?: number;
  size?: number;
  duration?: number;
  playOnce?: boolean;
}

const props = withDefaults(defineProps<GlareHoverProps>(), {
  background: "#000",
  color: "#ffffff",
  opacity: 0.5,
  angle: -45,
  size: 250,
  duration: 650,
  playOnce: false,
});

function parseHEX(color: string, opacity: number): string {
  const hex = color.replace("#", "");
  const parse = (h: string) => Number.parseInt(h, 16);
  if (/^[0-9A-Fa-f]{6}$/.test(hex)) {
    return `rgba(${parse(hex.slice(0, 2))},${parse(hex.slice(2, 4))},${parse(hex.slice(4, 6))},${opacity})`;
  }
  if (/^[0-9A-Fa-f]{3}$/.test(hex)) {
    return `rgba(${parse(hex[0] + hex[0])},${parse(hex[1] + hex[1])},${parse(hex[2] + hex[2])},${opacity})`;
  }
  return color;
}

const rgba = computed(() => parseHEX(props.color, props.opacity));

const cssVars = computed(() => ({
  "--gh-angle": `${props.angle}deg`,
  "--gh-duration": `${props.duration}ms`,
  "--gh-size": `${props.size}%`,
  "--gh-rgba": rgba.value,
  background: props.background,
  ...(props.width !== undefined ? { width: props.width } : {}),
  ...(props.height !== undefined ? { height: props.height } : {}),
}));

const rootClass = computed(() =>
  cn(
    "relative grid w-fit h-fit cursor-pointer place-items-center overflow-hidden bg-transparent",
    // BEFORE ELEMENT
    "before:pointer-events-none before:absolute before:inset-0 before:z-10 before:bg-no-repeat before:content-['']",
    // GRADIENT
    "before:[background-image:linear-gradient(var(--gh-angle),transparent_60%,var(--gh-rgba)_70%,transparent,transparent_100%)]",
    // SIZE + POSITION
    "before:[background-size:var(--gh-size)_var(--gh-size),100%_100%]",
    "before:[background-position:-100%_-100%,0_0]",
    // TRANSITION
    !props.playOnce &&
      "before:transition-[background-position] before:duration-[var(--gh-duration)] before:ease-in-out",
    props.playOnce &&
      "before:transition-none hover:before:transition-[background-position] hover:before:duration-[var(--gh-duration)]",
    // HOVER EFFECT
    "hover:before:[background-position:100%_100%,0_0]",
    props.class,
  ),
);
</script>

<template>
  <div :class="rootClass" :style="cssVars">
    <slot />
  </div>
</template>

Usage

The effect is implemented with a ::before pseudo-element: a linear-gradient tile moves from one corner to the opposite on hover. Color is parsed from hex (#rgb or #rrggbb) into rgba for the glare band.

vue
<script setup lang="ts">
import GlareHover from "@/components/spark-ui/glare-hover/glare-hover.vue";
</script>

<template>
  <GlareHover class="rounded-lg">
    <div>Hover to see the glare sweep</div>
  </GlareHover>
</template>

Examples

CTA

14-day free trial · No card required

Ready to get started?

Join 4,000+ teams already using our platform to ship faster.

Alerts

Action required
Your plan expires in 3 days. Renew to keep access.
Payment declined
Check your card details and try again.
Subscription confirmed
You have full Pro access until April 5, 2027.

Props

PropTypeDefaultDescription
classstringClasses on the root div (use rounded-*, overflow-hidden, etc.).
backgroundstring"#000"Root background color.
colorstring"#ffffff"Glare highlight (hex #rgb / #rrggbb).
opacitynumber0.5Alpha for the parsed glare color.
anglenumber-45Gradient angle in degrees (--gh-angle).
sizenumber250Glare tile size in % (--gh-size).
durationnumber650Transition duration in ms (--gh-duration).
playOncebooleanfalseIf true, animation runs on hover only (no transition until hover).
widthstringOptional width on the root style.
heightstringOptional height on the root style.

Slots

SlotDescription
defaultContent inside the wrapper.

Released under the MIT License.