This private block changes Horizon's standard variant picker to an "unselected start, selection required" pattern like Allbirds or Goldwin use. The product page starts with every option (color, size, etc.) unselected, and the Add to cart and Buy it now buttons stay disabled until the customer has chosen all of them.
[Required Prerequisite] This block only works correctly on Horizon v4.1.4 or later. On earlier versions (v3.2.1 through v4.1.1), collection listing product cards link via variant.url (a variant's own URL), so even a normal click from a listing page opens the product page with a variant already selected — which breaks the "unselected start" premise entirely. Shopify reverted this to product.url in Horizon v4.1.4. Please confirm your theme version before installing this block.

👉 You can see this live on the following demo store (starting with nothing selected, Add to cart disabled until every option is chosen).
horizon-store-q9zl2koe.myshopify.com/products/specialty-coffee-beans
Store password: store-dojo
What it looks like
Both color and size start with no "selected" fill at all. The Add to cart button turns gray, and its label changes to guide the customer toward whichever option is still missing, e.g. "Please select a color."

Tapping the disabled button highlights what's missing
If tapping the button simply did nothing, customers wouldn't know why they can't proceed. A nearly invisible transparent layer sits on top of the disabled button to catch the tap, and the moment it's tapped, the still-unselected option group is outlined in red with a guiding message.

How it works
◆ While an option group (color, size, etc.) is unconfirmed, the real element is hidden and a visual-only clone is inserted in its place. The clone is completely independent of Horizon's own state management, so its selection state (checked radios, select values) can be freely manipulated. The moment the customer picks something on the clone, a real click/change event is replayed on the corresponding real element, then the clone is removed and the real element shown again. The real element's own selection state is never rewritten directly, so this never conflicts with Horizon's own partial re-render (morph) or resolution logic.
◆ The Add to cart button isn't cloned or overlaid — its real disabled attribute and label text are rewritten directly. A genuinely disabled element reliably blocks submission regardless of how Horizon's own code adds items to the cart (even if it fetches directly on click). A dimmed-appearance-only approach risks the click event being routed around and the item actually being added.
◆ However, a disabled element never dispatches a click event at all, nor does it bubble to ancestors. So a nearly invisible transparent layer is placed on top of the real (still disabled) button to catch the tap and trigger the red-outline display on the unselected group. The "Buy it now" style instant-checkout button is a standard Shopify web component whose internals can't be touched, so it's disabled simply via pointer-events: none.
How to add it
◆ Shopify admin → Online Store → Themes → "…" → Edit code
◆ Create a new file _variant-picker-require-selection.liquid inside the blocks folder and paste in the code (the filename must start with an underscore so it's treated as a private block).
◆ Inside blocks/_product-details.liquid's schema, add one new block registration right after the variant-picker entry.

◆ In the theme editor's product page, swap the standard "Variant picker" block for the newly added "Variant picker (selection required)" block, and you're done.
Code excerpts
◆ The part that replays a clone's selection onto the real element as a genuine event.

◆ The part that disables the Add to cart button and wires up the transparent click-catching layer.

◆ Purchase this TIPS to get the full Liquid source for this "Require Variant Selection Picker."
Related TIPS:
Replace the standard variant picker with a new block that shows images
Wrap the standard variant picker in a card-style UI
Show extra notes like "+$100" or "made to order" on variant options
