Feature Highlight Cards — Icon Grid with Glow HTML CSS
Feature Highlight Cards · Cards · Plain HTML, CSS & JS · Live preview
What's included
Features
--mx and --my CSS custom properties track the cursor percentage position within each card. The ::before gradient centres on these values — a spotlight that follows the cursor.--ic (background) and --stroke (icon colour) are set inline per card — one HTML attribute controls the entire icon colour palette for each card..card-wide applies grid-column: span 2 — the hero feature card takes double width. Reverts to single column on mobile automatically..card-dark uses a deep indigo gradient background with light text — the "Free Forever" standout card uses it to break the visual pattern..card-link:hover increases gap from 4px to 7px — the arrow nudges right on hover via CSS transition, indicating the link destination.translateY(-3px) + box-shadow + border-color: #c7d2fe on hover — a three-property lift that makes cards feel interactive and slightly elevated.repeat(3, 1fr) on desktop, two-column on tablet, single-column on mobile — the wide card reverts gracefully at each breakpoint.About this UI Snippet
Feature Cards — Mouse-Tracking Radial Glow, CSS Custom Property Grid & Icon Badge System

Feature highlight cards are a cornerstone of SaaS landing pages — presenting product capabilities in a scannable, visually distinct grid. This snippet builds a six-card feature grid with a mouse-tracking radial glow effect, colour-coded icon badge system, tag chips, arrow CTA links, a wide (spanning two columns) card variant for the hero feature, and a dark gradient card for the standout "Free Forever" proposition.
Feature card grids appear on virtually every SaaS, developer tool, and product landing page. The design challenge is making each card feel distinct while maintaining visual cohesion. Icon colour coding, tag chips, and the CTA arrow link pattern solve this — plus the mouse-tracking glow adds a premium interactive feel that differentiates from static card grids.
Mouse-tracking radial glow per card
Each card's ::before pseudo-element renders a radial-gradient centred at CSS custom properties --mx and --my. The mousemove event listener reads the mouse position relative to the card's getBoundingClientRect and sets these properties as percentage values. The gradient appears at opacity: 0 by default and transitions to opacity: 1 on hover. The result is a "spotlight" effect that follows the cursor within each card — a pattern used in Linear, Vercel, and Raycast landing pages.
The key implementation detail is setting --mx and --my on the element (not in a stylesheet) — inline custom properties override the 50% 50% default set in CSS, placing the gradient precisely under the cursor. This requires only one getBoundingClientRect call per mousemove event and no requestAnimationFrame throttling for smooth 60fps behaviour.
Colour-coded icon badge system
Each card's icon container uses two CSS custom properties: --ic (background) and --stroke (icon colour). These are set inline on each card's .card-icon element. The palette — indigo, sky, emerald, amber, pink, indigo-dark — is drawn from a consistent design token system. This approach means adding a new colour variant is a one-line HTML change.
Wide card with `grid-column: span 2`
The "175+ UI Snippets" card spans two columns via grid-column: span 2. This creates visual hierarchy — the most important feature gets double the width. The card layout adapts without additional CSS because the flex column stretches naturally within the wider container. On mobile (max-width: 640px), the grid switches to single column and the wide card reverts to normal width. Pair with a bento grid for more complex asymmetric feature layouts.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You don't have to guess why the glow only takes one getBoundingClientRect call per mouse move to feel smooth. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why setting the mx and my custom properties inline on each card element overrides the 50 percent default baked into the stylesheet, and why that inline-override approach avoids needing requestAnimationFrame throttling for 60fps tracking. The same assistant can help optimize it — ask whether attaching a separate mousemove listener to every card versus one delegated listener on the grid container matters as the number of cards grows, and whether the glow's radial-gradient opacity transition should be shortened on cards with a lot of hover traffic. It's also useful for extending the grid: ask it to make the glow color per-card instead of one fixed indigo everywhere, add a staggered scroll-in reveal using IntersectionObserver, or turn the wide hero card into a small carousel that rotates through multiple featured items. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a feature card grid with a mouse-tracking radial glow effect in plain HTML, CSS, and JavaScript — no library.
Requirements:
- A responsive CSS grid of cards (three columns on desktop collapsing to fewer on smaller screens), where one card can span two grid columns to act as a visually larger hero feature, and at least one card uses a distinct dark gradient background variant.
- Each card must have a pseudo-element layer with a radial-gradient background positioned via two CSS custom properties representing the horizontal and vertical percentage position of the pointer within that specific card, defaulting to the card's center when no custom properties have been set yet.
- On mousemove over a card, compute the pointer's position as a percentage of that card's own width and height using its bounding rectangle, then write those two percentages directly onto that card element's inline style as CSS custom properties, so the glow follows the cursor precisely within card-local coordinates rather than page coordinates.
- The glow layer must be invisible by default and fade to visible only while the pointer is within that specific card, using an opacity transition, and must never intercept clicks or interfere with the card's other content.
- Give each card's icon badge its own background and icon stroke color driven by two per-card CSS custom properties, so adding a new color variant requires setting only those two values rather than duplicating any CSS rules.
- Add a footer row per card containing small tag chips and a call-to-action link whose icon visually nudges further away from its text on hover via a CSS transition on a flex gap value.
- Ensure the whole grid still reads correctly and the wide card correctly reverts to a normal single-column width when the layout collapses to one column on narrow viewports.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Paste HTML, CSS, and JSSix feature cards appear in a 3-column grid on a light background. The first card spans two columns. The last card has a dark gradient background.
- 2Move your mouse slowly across a cardA radial glow follows your cursor within the card boundary — the spotlight effect centres exactly under the pointer and fades out when you leave.
- 3Hover over the arrow linksThe gap between the link text and arrow icon increases on hover — a subtle micro-interaction that communicates interactivity.
- 4Inspect the icon colour systemEach card's icon has a different background and stroke colour defined via
--icand--strokeCSS custom properties inline on the element. - 5Update card contentSwap icon SVGs, change titles, descriptions, and tag chips. Change the glow colour by adjusting the rgba in the
::beforegradient in CSS. - 6Add or remove cardsAdd
<article class="card">to the grid. Usecard-widefor a card that spans 2 columns. Usecard-darkfor the dark variant. The grid adapts automatically.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
The glow colour is hardcoded as rgba(99,102,241,.12) in the ::before gradient in CSS. To make it per-card, add a --glow CSS custom property to each card: card.style.setProperty('--glow', 'rgba(16,185,129,.12)'). In CSS: radial-gradient(circle..., var(--glow, rgba(99,102,241,.12))....
Use an IntersectionObserver: observe all cards and add an .in-view class when they enter the viewport. In CSS: .card { opacity:0; transform:translateY(20px); transition:opacity .5s,transform .5s } and .card.in-view { opacity:1; transform:none }. Add staggered delays based on the card index.
Define a FeatureCard component accepting {icon, iconBg, iconColor, title, desc, tags, link, wide, dark} props. The grid is the parent component mapping a features data array. The mouse-tracking uses onMouseMove and useRef to access the card's bounding rect.
Change grid-template-columns: repeat(3, 1fr) to repeat(2, 1fr) and remove the .card-wide class or change it to grid-column: span 1. Adjust card widths via max-width on the grid container.