Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Designing For TV: The Evergreen Pattern That Shapes TV Experiences

      August 27, 2025

      Amplitude launches new self-service capabilities for marketing initiatives

      August 27, 2025

      Microsoft packs Visual Studio August update with smarter AI features

      August 27, 2025

      Optimizing PWAs For Different Display Modes

      August 26, 2025

      Why this $25 ratchet tool beats any multitool or Swiss Army Knife I’ve ever tested

      August 28, 2025

      One of my favorite sports watches from 2024 just got upgrades in all the right places

      August 28, 2025

      Google’s AI Mode is getting more links for you not to click on

      August 28, 2025

      I still prefer Apple Watch over Oura Ring for 3 key reasons – but there is one big drawback

      August 28, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Heartbeat Collection Method in Laravel 12.26; Wayfinder Now in React and Vue Starter Kits

      August 28, 2025
      Recent

      Heartbeat Collection Method in Laravel 12.26; Wayfinder Now in React and Vue Starter Kits

      August 28, 2025

      spatie/laravel-rdap

      August 28, 2025

      mvanduijker/laravel-mercure-broadcaster

      August 28, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Geekom’s A9 Max mini PC is so good that I want to turn off my desktop gaming rig — and it’s not bad at AI, either

      August 28, 2025
      Recent

      Geekom’s A9 Max mini PC is so good that I want to turn off my desktop gaming rig — and it’s not bad at AI, either

      August 28, 2025

      ‘There Are No Ghosts At The Grand’ looks glorious — I’m more excited than ever for this upcoming Xbox Game Pass release

      August 28, 2025

      Epic Games CEO Tim Sweeney says Unreal Engine 5’s performance problems aren’t about the engine — they’re about when developers choose to optimize

      August 28, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»News & Updates»A Radio Button Shopping Cart Trick

    A Radio Button Shopping Cart Trick

    August 27, 2025

    Editor’s note: This is a really clever idea that Preethi shared, but you will also see that it comes with accessibility drawbacks because it uses duplicated interactive elements. There are other ways to approach this sort of thing, as Preethi mentions, and we’ll look at one of them in a future article.

    Two large pizzas for yourself, or twelve small ones for the kids party — everyone’s gone through the process of adding items to an online cart. Groceries. Clothing. Deli orders. It’s great when that process is simple, efficient, and maybe even a little quirky.

    This post covers a design referred as infinite selection. Metaphorically infinite.

    Here’s how it works:

    CodePen Embed Fallback

    That’s right, you click an item and it jumps right into the shopping cart, complete with a smooth transition that shows it happening. You can add as many items as you want!

    And guess what: all of it is done in CSS — well, except the part that keeps count of selected items — and all it took is a combination of radio form inputs in the markup.

    I’m going to walk you through the code, starting with the layout, but before that, I want to say up-front that this is just one approach. There are for sure other ways to go about this, and this specific way comes with its own considerations and limitations that we’ll get into.

    The Layout

    Each item (or product, whatever you want to call it) is a wrapper that contains two radio form inputs sharing the same name value — a radio group.

    <div class="items flat-white">
      <input type="radio" name="r3" title="Flat White">
      <input type="radio" name="r3" title="Flat White">
    </div>

    When you check one in a duo, the other gets unchecked automatically, leading to a see-saw of check and uncheck between the two, no matter which one is clicked.

    Each item (or radio group) is absolutely positioned, as are the two inputs it contains:

    .items {   
      position: absolute;
    
      input { 
        position: absolute; 
        inset: 0; 
      }
    }

    The inset property is stretching the inputs to cover the entire space, making sure they are clickable without leaving any dead area around them.

    Now we arrange everything in a layout. We’ll use translate to move the items from a single point (where the centered cart is) to another point that is a litte higher and spread out. You can code this layout anyway you like, as long as the radio buttons inside can make their way to the cart when they are selected.

    .items {
      --y: 100px; /* Vertical distance from the cart */
    
      &:not(.cart) {
        transform: translate(var(--x), calc(-1 * var(--y)));
      }
      &.espresso { 
        --x: 0px;  /* Horizontal dist. from the cart */
      }
      &.cappuccino { 
        --x: -100%; 
      }
      &.flat-white { 
        --x: 100%; 
      }
    }

    So, yeah, a little bit of configuration to get things just right for your specific use case. It’s a little bit of magic numbering that perhaps another approach could abstract away.

    Selecting Items

    When an item (<input>) is selected (:checked), it shrinks and moves (translate) to where the cart is:

    input:checked {
      transform: translate(calc(-1 * var(--x)), var(--y)) scale(0);
    }

    What happens under the hood is that the second radio input in the group is checked, which immediately unchecks the first input in the group, thanks to the fact that they share the same name attribute in the HTML. This gives us a bit of boolean logic a là the Checkbox Hack that we can use to trigger the transition.

    So, if that last bit of CSS moves the selected item to the shopping cart, then we need a transition to animate it. Otherwise, the item sorta zaps itself over, Star Trek style, without you telling.

    input:checked{
      transform: translate(calc(-1 * var(--x)), var(--y)) scale(0);
      transition: transform .6s linear;
    }

    Keeping Count

    The whole point of this post is getting a selected item to the cart. There’s no “Cart” page to speak of, at least for the purposes of this demo. So, I thought it would be a good idea to show how many items have been added to the cart. A little label with the count should do the trick.

    let n = 0;
    const CART_CNT = document.querySelector("output");
    document.querySelectorAll("[type='radio']").forEach(radio => {
      radio.onclick = () => {
        CART_CNT.innerText = ++n;
        CART_CNT.setAttribute("arial-label", `${n}`)
      }
    });

    Basically, we’re selecting the cart object (the <output> element) and, for each click on a radio input, we increase an integer that represents the count, which is slapped onto the shopping card icon as a label. Sorry, no removing items from the cart for this example… you’re completely locked in. 😅

    Accessibility?

    Honestly, I wrestled with this one and there probably isn’t a bulletproof way to get this demo read consistently by screen readers. We’re working with two interactive elements in each group, and need to juggle how they’re exposed to assistive tech when toggling their states. As it is, there are cases where one radio input is read when toggling into an item, and the other input is read when toggling back to it. In other cases, both inputs in the groups are announced, which suggests multiple options in each group when there’s only one.

    I did add a hidden <span> in the markup that is revealed with keyboard interaction as a form of instruction. I’ve also inserted an aria-label on the <output> that announces the total number of cart items as they are added.

    Here’s the final demo once again:

    CodePen Embed Fallback

    Maybe Use View Transitions Instead?

    I wanted to share this trick because I think it’s a clever approach that isn’t immediately obvious at first glance. But this also smells like a situation where the modern View Transition API might be relevant.

    Adrian Bece writes all about it in a Smashing Magazine piece. In fact, his example is exactly the same: animating items added to a shopping cart. What’s nice about this is that it only takes two elements to build the transition: the item and the cart label. Using CSS, we can hook those elements up with a view-transition-name, define a @keyframes animation for moving the item, then trigger it on click. No duplicate elements or state juggling needed!

    Alternatively, if you’re working with just a few items then perhaps a checkbox input is another possible approach that only requires a single element per item. the downside, of course, is that it limits how many items you can add to the card.

    But if you need to add an infinite number of items and the View Transition API is out of scope, then perhaps this radio input approach is worth considering.


    A Radio Button Shopping Cart Trick originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    Source: Read More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleASRock Industrial NUC BOX-255H Running Linux: Intel Core Ultra 7 Processor 255H
    Next Article How to use GitHub Copilot on github.com: A power user’s guide

    Related Posts

    News & Updates

    Why this $25 ratchet tool beats any multitool or Swiss Army Knife I’ve ever tested

    August 28, 2025
    News & Updates

    One of my favorite sports watches from 2024 just got upgrades in all the right places

    August 28, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    CVE-2025-4575 – OpenSSL -addreject Option Truncation Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-6651 – PDF-XChange Editor JP2 File Parsing Remote Code Execution Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-4422 – Lenovo SMB Relay Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    This 360Hz QD-OLED monitor is more than magnificent — and it’s $280 off right now

    News & Updates

    Highlights

    CVE-2025-49128 – Jackson-core Information Disclosure Vulnerability

    June 6, 2025

    CVE ID : CVE-2025-49128

    Published : June 6, 2025, 10:15 p.m. | 1 hour, 34 minutes ago

    Description : Jackson-core contains core low-level incremental (“streaming”) parser and generator abstractions used by Jackson Data Processor. Starting in version 2.0.0 and prior to version 2.13.0, a flaw in jackson-core’s `JsonLocation._appendSourceDesc` method allows up to 500 bytes of unintended memory content to be included in exception messages. When parsing JSON from a byte array with an offset and length, the exception message incorrectly reads from the beginning of the array instead of the logical payload start. This results in possible information disclosure in systems using pooled or reused buffers, like Netty or Vert.x. This issue was silently fixed in jackson-core version 2.13.0, released on September 30, 2021, via PR #652. All users should upgrade to version 2.13.0 or later. If upgrading is not immediately possible, applications can mitigate the issue by disabling exception message exposure to clients to avoid returning parsing exception messages in HTTP responses and/or disabling source inclusion in exceptions to prevent Jackson from embedding any source content in exception messages, avoiding leakage.

    Severity: 4.0 | MEDIUM

    Visit the link for more details, such as CVSS details, affected products, timeline, and more…

    Bookmark – terminal-based bookmark manager

    May 1, 2025

    CVE-2025-25037 – Aquatronica Controller System Information Disclosure Vulnerability

    June 20, 2025

    CVE-2025-5621 – D-Link DIR-816 OS Command Injection Vulnerability

    June 4, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.