22 CSS Star Ratings

12 Pure CSS10 Light JSPublished

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

Course pickPartner: Zero to Mastery

Affiliate link

Want to build production-ready CSS layouts, animations and UI from scratch?

You just browsed 22 star ratings. Learn the Flexbox, Grid and animation thinking behind them, so the next component starts in your head, not in a copy-paste.

10% off at checkout with code
Check ZTM Course

Every ZTM course in one membership: $25/month, paid yearly at $299 · 30‑day money-back guarantee

The CSS Bootcamp. We may earn a commission, at no extra cost to you.

Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

16. Holographic Scanner Rating (opens in a new tab)

Published

CSS + JS
A terminal-aesthetic rating widget with a sweeping green CSS scan beam, CRT scanline overlay, corner bracket chrome, and a score that scrambles via JS character substitution before resolving cleanly on selection.
FAQ

Frequently asked questions

How do I create a pure CSS star rating without JavaScript?
Two patterns cover almost every case. (1) The classic radio-button + reverse-flex trick (Demo 01): wrap five <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.
How do I make a half-star rating display in CSS?
The trick is layering two stars on top of each other: a gray background star (full width) and a gold foreground star clipped to a percentage. Demo 03 (CSS Half Star Rating) ships the full recipe. The HTML wraps each star in a <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.
How do I make my star rating accessible to screen readers?
Five rules: (1) Wrap the rating in a <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.
What's the difference between an interactive and a read-only star rating?
Interactive ratings let the user *submit* a rating — they need real form inputs (<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.
How do I add half-star precision to my read-only ratings?
For a fixed display showing a specific decimal (4.5, 3.7, 4.2 stars), layer two stars and clip the gold one to (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.
Can I use CSS-only star ratings without losing Lighthouse accessibility scores?
Yes — if you keep semantic HTML. Lighthouse's accessibility audit checks for: (1) form inputs having associated labels (yes if you use <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.
How do I customize the star color or size at runtime?
CSS custom properties (variables) are the answer. Demo 09 (CSS Variable Star Customizer) ships the full recipe. Define theme tokens on the wrapper: .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.
How is this different from FreeFrontend, FrontendPlanet, W3Schools, dev.to, or rating libraries like React Stars / Vue Star Rating?
Three differentiators. **(1) Scope isolation**: every demo lives under a unique .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.

Related collections

15 CSS 3D Tilt Hover Cards preview

15 CSS 3D Tilt Hover Cards

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 CSS Animated Cards preview

24 CSS Animated Cards

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 CSS Avatars preview

22 CSS Avatars

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.

Search CodeFronts

Loading…