DEV Community

Cover image for Building a Card with Gradient Hover Effect Inspired by Nuxt UI
Tanay Karnik
Tanay Karnik

Posted on • Originally published at tanay.xyz

11 2 2 2 3

Building a Card with Gradient Hover Effect Inspired by Nuxt UI

I came across an amazing card hover effect on the Nuxt UI website.

Unfortunately, it’s a pro component—so I decided to build it myself!

I tried getting some inspiration by inspecting their code, but it was more complex than I expected.
I'm no CSS wizard, so I came up with a much simpler version of this effect.

Here’s a tutorial on how to make a card with a cool gradient hover effect using TailwindCSS.


1. Set up a simple card component

<template>
  <div :class="['bg-neutral-950', props.class || '']"></div>
</template>

<script setup>
const props = defineProps(["class"]);
</script>
Enter fullscreen mode Exit fullscreen mode

Let’s start by building a basic card component with a black background, arranged in a grid.

This setup will be our testing ground.

I'm using Vue here, but this can be easily replicated with React, Vanilla JS, or any other framework.

Step 1 Demo


2. Add a circular gradient that follows the mouse

<template>
  <div
    ref="target"
    :style="cssVars"
    :class="['shine bg-neutral-950', props.class || '']"
  ></div>
</template>

<script setup>
import { ref, computed } from "vue";
import { useMouseInElement } from "@vueuse/core";
const props = defineProps(["class"]);
const target = ref(null);
const { elementX, elementY } = useMouseInElement(target);
const cssVars = computed(() => ({
  "--x": `${target.value ? elementX.value : -1000}px`,
  "--y": `${target.value ? elementY.value : -1000}px`,
}));
</script>

<style scoped>
.shine {
  background-image: radial-gradient(
    300px circle at var(--x) var(--y),
    #6366f1 0,
    transparent 100%
  );
}
</style>
Enter fullscreen mode Exit fullscreen mode

The next step is adding a circular gradient that follows the mouse.

  1. First, add a shine class to the card div and set it up with a radial-gradient.
  2. This gradient is centered at CSS variables --x and --y, going from bright (any color) at the center to fully transparent, with a 300px radius (adjustable).

To make the gradient follow the mouse, I’m using a useMouseElement composable. Here, elementX and elementY are the mouse coordinates relative to the position of the target element.

Depending on your framework, you could use a different hook or add a mousemove event listener to update these CSS variables.

Step 2 Demo


3. Stacking divs

<template>
  <div
    ref="target"
    :style="cssVars"
    :class="['p-[2px] shine bg-neutral-950', props.class || '']"
  >
    <div class="w-full h-full bg-neutral-950/80"></div>
  </div>
</template>

<script setup>
import { ref, computed } from "vue";
import { useMouseInElement } from "@vueuse/core";
const props = defineProps(["class"]);
const target = ref(null);
const { elementX, elementY } = useMouseInElement(target);
const cssVars = computed(() => ({
  "--x": `${target.value ? elementX.value : -1000}px`,
  "--y": `${target.value ? elementY.value : -1000}px`,
}));
</script>

<style scoped>
.shine {
  background-image: radial-gradient(
    300px circle at var(--x) var(--y),
    #6366f1 0,
    transparent 100%
  );
}
</style>
Enter fullscreen mode Exit fullscreen mode

I know what you’re thinking—it doesn’t look like the final card effect at all.

The trick to achieving the right look is to stack another div on top with a small amount of padding (I used 2px).

There are other ways to achieve this effect, like using ::before pseudo-elements or Tailwind rings, but I found this to be the simplest and cleanest approach.

Step 3 Demo


4. Finishing touches

<template>
  <div
    ref="target"
    :style="cssVars"
    :class="['rounded-[15px] p-[2px] shine', props.class || '']"
  >
    <div
      class="rounded-[13px] w-full h-full bg-gradient-to-b from-neutral-800/50 to-neutral-950/50 bg-neutral-950/80"
    ></div>
  </div>
</template>

<script setup>
import { ref, computed } from "vue";
import { useMouseInElement } from "@vueuse/core";
const props = defineProps(["class"]);
const target = ref(null);
const { elementX, elementY } = useMouseInElement(target);
const cssVars = computed(() => ({
  "--x": `${target.value ? elementX.value : -1000}px`,
  "--y": `${target.value ? elementY.value : -1000}px`,
}));
</script>

<style scoped>
.shine {
  background-image: radial-gradient(
    300px circle at var(--x) var(--y),
    #6366f1 0,
    transparent 100%
  );
}
</style>
Enter fullscreen mode Exit fullscreen mode

Finally, give the outer div a subtle background gradient and rounded borders.

To keep the padding and border-radius looking clean, I added 2px to the border radius of the outer div (general tip: adjust by padding * 1.141 for a proportional look).

Step 4 Demo


Here's the GitHub repo to see the code in action:

Shiny Cards

Nuxt shiny card hover effect.




Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay