
Pure CSS Interactive Star Rating
Published
22 production-grade CSS star rating designs you can copy-paste into any project — pure CSS radio-button stars with reverse-flex sibling fill, modern :has() sibling combinator pattern, half-star fractional precision, animated bursting SVG particles, accessible ARIA fieldset rating, read-only review display, emoji feedback reaction scale (😞😐🙂😊😍), neumorphic soft-UI stars, CSS variable live customizer, vertical sidebar e-commerce filter (Amazon-style "4★ & up"), gradient-filled luxury stars, single-star numeric ticker, heart-based favorite scale, tooltip hover labels, plus 8 experimental concepts: liquid mercury morphing, holographic scanner, neural pulse feedback, magnetic field lines, quantum superposition, DNA helix strand, particle constellation, and glitch corrupt-and-resolve. Every star scoped under a unique .sr-NN prefix so all 22 coexist on this page without style bleed; every @keyframes name namespaced sr-NN-*; every @media (prefers-reduced-motion: reduce) guard already wired in. Real <fieldset> + <legend> + <input type="radio"> markup on interactive demos so screen readers announce ratings correctly.
Related25 CSS Testimonials & Reviews24 CSS Radio Buttons18 CSS Product Cards

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published
<input type="radio" name="rating"> elements in a container with flex-direction: row-reverse, so earlier inputs (higher star values) sit to the right in the DOM but render left-to-right visually. Use the ~ general sibling combinator (input:checked ~ label::before) to fill every label *after* the hovered or checked one — which in reversed order means all stars of lower value — creating the cascade fill purely in CSS. (2) The modern :has() pattern (Demo 02): keep the inputs in natural DOM order and use .stars:has(#s4:checked) label[for^="s1"] ::before { color: gold } to drive fills from the parent. :has() is supported in all modern browsers as of 2023; if you need to support older Safari/Firefox, fall back to the reverse-flex trick. Both patterns are 100% CSS — no JS, no libraries — and stay keyboard-accessible because the native radio inputs handle focus, arrow keys, and form submission. Every demo in this collection ships the full HTML + CSS so you can paste it into your project.<span class="star"> with two child elements (or two pseudo-elements). The gold layer uses clip-path: inset(0 50% 0 0) (right-side cut) for an exact half, or width: 50%; overflow: hidden for variable precision. For a read-only display showing 4.5 stars: the first four are fully gold, the fifth gets 50% gold-layer width. For variable values (e.g. 4.3), compute (value % 1) * 100% and inline the result on the partial star — CSS-only, no JS needed if you generate the markup server-side. Every Amazon, Yelp, and Trustpilot review widget you've ever seen uses some variant of this exact pattern.<fieldset> with a <legend> describing what's being rated ("Rate this product"), so screen readers announce the context. (2) Each star is a real <input type="radio"> paired with a real <label> — never style a <div> to look like a star unless you fully implement the ARIA radiogroup pattern with keyboard handlers. (3) Visually hide the radio buttons with clip-path: inset(50%) or position: absolute; opacity: 0 (NOT display: none, which removes them from the accessibility tree). (4) Give each label visible-only text like <span class="sr-only">1 star</span> so a screen reader announces "1 star, radio button" instead of just "radio button". (5) Add a clear :focus-visible outline on the labels so keyboard users see where focus is. Demo 05 (Accessible ARIA Star Rating) ships all five rules with a real <fieldset> + <legend>, screen-reader-only labels, focus rings, and arrow-key navigation (free from the native radio group). Cite WCAG 2.1 SC 1.3.1 (Info & Relationships) and 4.1.2 (Name, Role, Value) in your audit notes.<input type="radio">) so the value posts with the form, focus and arrow keys work, and the value is available to JavaScript via form.elements.rating.value. Read-only ratings just *display* an existing aggregate value ("4.5 stars from 312 reviews") — they don't need inputs at all; use semantic markup like <output> with aria-label="Rated 4.5 out of 5 stars" so screen readers announce the value, then style with the same star clip-path approach as Demo 06. Common mistake: shipping interactive markup for a read-only display — it adds DOM weight, makes screen readers prompt "radio button: select to change" (confusing for a display value), and the focus ring traps keyboard users in non-functional widgets. Demo 06 is the read-only reference; Demos 01, 02, 03, 05 are the interactive references.(value % 1) * 100% width. The arithmetic: if value is 4.5, render the first 4 stars fully gold, the 5th with width: 50%. If value is 4.3, the 5th star is 30%. Three approaches: (a) **inline style** — server renders <span style="width: 30%"> on the partial star. Simplest, no JS. (b) **CSS custom property** — <div style="--rating: 4.3"> and CSS calculates width: calc(var(--rating) * 20%). Cleaner data binding. (c) **CSS conic-gradient** — single SVG star path filled with a conic gradient where gold ends at (value / 5) * 360deg. Most elegant but trickier to get right at small sizes. Demo 03 (interactive) and Demo 06 (read-only) cover all three approaches. For dynamic values from an API, approach (b) is usually best — JS just updates the CSS variable, the CSS handles the visual update.<label for> paired with <input>); (2) sufficient color contrast (yes if your gold passes 3:1 against the unfilled gray; check with the WebAIM Contrast Checker — #FFB000 on #fff is 1.97:1 against text but passes the 3:1 "non-text contrast" requirement for UI components in WCAG 2.1); (3) keyboard accessibility (yes — native radio groups handle arrow keys); (4) screen-reader announcements (yes if you wrap in <fieldset> + <legend>); (5) focus visibility (yes if you add :focus-visible outlines). Demo 05 (Accessible ARIA) ships all five — drop it into your page and Lighthouse will score it 95-100 on accessibility. Common Lighthouse failure: hiding inputs with display: none instead of clip-path removes them from the a11y tree and breaks every screen reader. Use clip-path: inset(50%); position: absolute instead — visually identical, accessibility-tree-intact..sr-09 { --star-fill: #FFB000; --star-empty: #e5e7eb; --star-size: 36px; --star-gap: 8px }. Then reference them in every internal rule: .sr-09__star { width: var(--star-size); height: var(--star-size); fill: var(--star-empty) } and .sr-09__star.is-filled { fill: var(--star-fill) }. Now JavaScript (or even another CSS rule based on data-theme="dark") can update the variables and every star recolors at once: el.style.setProperty('--star-fill', '#ec4899'). The same approach scales sizes (40px → 60px for a hero CTA), spacing, animation duration, and even the star shape (swap clip-path polygons for different star styles). For React, pass variables as inline style: <div style={{ '--star-fill': brandColor }}>. For Tailwind, use [--star-fill:#FFB000] arbitrary-value syntax. No re-compile, no rebuild — just update the variable..sr-NN namespace (no collision when pasting two demos into one project), every @keyframes is prefixed sr-NN-*, every element ID is sr-NN-*. The big gallery sites (FreeFrontend, FrontendPlanet, uiCookies) curate links to CodePen demos with generic class names like .rating, .stars, .star that collide when pasted together. **(2) Modern patterns**: this collection ships both the *classic* radio-button + reverse-flex pattern (works everywhere) AND the *modern* :has() pattern (Chrome 105+, Safari 15.4+, Firefox 121+ — 95%+ browser support today). W3Schools and most tutorial sites still teach only the reverse-flex hack and never mention :has(). **(3) Accessibility by default**: every interactive demo ships a real <fieldset> + <legend>, real <input type="radio"> + <label>, clip-path: inset(50%) hiding (not display: none), :focus-visible outlines, and prefers-reduced-motion guards. React-Stars / Vue-Star-Rating libraries are ~5-15KB gzipped, render their own DOM (often missing real form inputs), and need wrapper code for accessibility. This collection: 0 KB of dependencies, real form inputs, MIT-licensed, no signup. Free, copy-paste, ship today.15 mouse-aware 3D tilt hover cards — e-commerce product spotlight, glassmorphism parallax team card, interactive pricing tier, holographic NFT collectible, pop-out mascot, dark tech grid with border glow, media player album art, blog article preview, cyberpunk neon glow, dashboard KPI widget, minimalist real estate, flip-to-back tilt, mobile app showcase, course learning card, and a Pure CSS touch-friendly tilt. Vanilla JS writes --rx/--ry/--mx/--my; all rendering stays in CSS on the GPU.
24 hand-coded CSS animated card patterns organised by what triggers the motion, not by card style. Scroll and entrance triggers: staggered grid reveals, @starting-style mount-in, scroll-driven scale and fade on animation-timeline: view(), View Transitions API card-to-detail morphs, blur-to-sharp lazy image loading, and FLIP re-layout when a filter changes. State-change triggers: add-to-cart success morph, like and save particle burst, expand and collapse to intrinsic height with calc-size(), swipe-to-dismiss on Pointer Events, and skeleton-to-loaded crossfade. Data-driven triggers: count-up KPI metrics, SVG sparkline draw-on-enter, and progress ring fill on load. Ambient idle loops: breathing glow, floating drift, animated gradient mesh backgrounds, conic rotating borders, auto-cycling testimonial decks, and live status pulses. Plus four hover patterns where the effect is the topic itself: cursor spotlight, holographic foil glare, corner ribbon slide, and horizontal accordion expand. Every card is scoped under a .ac-NN prefix for no-collision pasting, guards prefers-reduced-motion, animates compositor-only properties, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.
22 hand-coded CSS avatars for chat apps, team dashboards, comment threads, account menus, and social profiles. Covers circular and squircle shapes, gradient and conic story rings, hexagon clip-path crops, online status dots, notification count badges, verified checkmarks, stacked facepiles with plus-N overflow, initials fallbacks for users without photos, broken-image recovery, avatar pickers, and a size scale system where the ring, badge, and status dot all scale from a single custom property.