{"product_id":"2026-08-28","title":"Horizon: \"Unselected Start\" Picker That Disables Add to Cart Until All Variants Are Selected","description":"\u003cp\u003e\u003cspan\u003eThis 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.\u003c\/span\u003e\u003c\/p\u003e\n\n\u003cp\u003e\u003cstrong style=\"color:#e0301e;\"\u003e[Required Prerequisite] This block only works correctly on Horizon v4.1.4 or later.\u003c\/strong\u003e On earlier versions (v3.2.1 through v4.1.1), collection listing product cards link via \u003ccode\u003evariant.url\u003c\/code\u003e (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 \u003ccode\u003eproduct.url\u003c\/code\u003e in Horizon v4.1.4. Please confirm your theme version before installing this block.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"Required prerequisite: how the product-card URL differs before and after Horizon v4.1.4\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-08-28_3_en.png?v=1787883562\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003e👉 You can see this live on the following demo store (starting with nothing selected, Add to cart disabled until every option is chosen).\u003cbr\u003e\u003ca href=\"https:\/\/horizon-store-q9zl2koe.myshopify.com\/products\/specialty-coffee-beans?preview_theme_id=138372841680\" target=\"_blank\" rel=\"noopener\"\u003ehorizon-store-q9zl2koe.myshopify.com\/products\/specialty-coffee-beans\u003c\/a\u003e\u003cbr\u003eStore password: store-dojo\u003c\/p\u003e\n\n\u003cp\u003e\u003cbr\u003e\u003c\/p\u003e\n\n\u003cdiv class=\"divider\"\u003e\u003c\/div\u003e\n\n\u003ch3\u003eWhat it looks like\u003c\/h3\u003e\n\u003cp\u003eBoth 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.\"\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"Result: the page starts with every option unselected and the Add to cart button disabled\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-08-28_1_en.png?v=1787884275\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003e\u003cbr\u003e\u003c\/p\u003e\n\n\u003ch3\u003eTapping the disabled button highlights what's missing\u003c\/h3\u003e\n\u003cp\u003eIf 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.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"Result: tapping the button outlines the unselected option in red with a message\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-08-28_2_en.png?v=1787884276\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003e\u003cbr\u003e\u003c\/p\u003e\n\n\u003cdiv class=\"divider\"\u003e\u003c\/div\u003e\n\n\u003ch3\u003eHow it works\u003c\/h3\u003e\n\u003cp\u003e◆ 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.\u003c\/p\u003e\n\u003cp\u003e◆ The Add to cart button isn't cloned or overlaid — its real \u003ccode\u003edisabled\u003c\/code\u003e attribute and label text are rewritten directly. A genuinely \u003ccode\u003edisabled\u003c\/code\u003e 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.\u003c\/p\u003e\n\u003cp\u003e◆ However, a \u003ccode\u003edisabled\u003c\/code\u003e 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 \u003ccode\u003epointer-events: none\u003c\/code\u003e.\u003c\/p\u003e\n\n\u003ch3\u003eHow to add it\u003c\/h3\u003e\n\u003cp\u003e◆ Shopify admin → Online Store → Themes → \"…\" → Edit code\u003c\/p\u003e\n\u003cp\u003e◆ Create a new file \u003ccode\u003e_variant-picker-require-selection.liquid\u003c\/code\u003e inside the \u003ccode\u003eblocks\u003c\/code\u003e folder and paste in the code (the filename must start with an underscore so it's treated as a private block).\u003c\/p\u003e\n\u003cp\u003e◆ Inside \u003ccode\u003eblocks\/_product-details.liquid\u003c\/code\u003e's schema, add one new block registration right after the \u003ccode\u003evariant-picker\u003c\/code\u003e entry.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"Change: add the block registration to blocks\/_product-details.liquid's schema\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-08-28_4_en.png?v=1787883562\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003e\u003cbr\u003e\u003c\/p\u003e\n\n\u003cp\u003e◆ 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.\u003c\/p\u003e\n\n\u003ch3\u003eCode excerpts\u003c\/h3\u003e\n\u003cp\u003e◆ The part that replays a clone's selection onto the real element as a genuine event.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"Code excerpt: replaying a clone's selection onto the real element\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-08-28_5_en.png?v=1787883562\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003e\u003cbr\u003e\u003c\/p\u003e\n\n\u003cp\u003e◆ The part that disables the Add to cart button and wires up the transparent click-catching layer.\u003c\/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"Code excerpt: disabling the Add to cart button and wiring the click catcher\" src=\"https:\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-08-28_6_en.png?v=1787883562\" class=\"zoomable-image\" style=\"max-width:100%;height:auto;\"\u003e\u003c\/p\u003e\n\n\u003cp\u003e\u003cbr\u003e\u003c\/p\u003e\n\n\u003cp\u003e◆ Purchase this TIPS to get the full Liquid source for this \"Require Variant Selection Picker.\"\u003c\/p\u003e\n\n\u003cdiv class=\"divider\"\u003e\u003c\/div\u003e\n\n\u003cp\u003eRelated TIPS:\u003cbr\u003e\n\u003ca href=\"\/en-us\/products\/2026-08-08\"\u003eReplace the standard variant picker with a new block that shows images\u003c\/a\u003e\u003cbr\u003e\n\u003ca href=\"\/en-us\/products\/2026-08-05\"\u003eWrap the standard variant picker in a card-style UI\u003c\/a\u003e\u003cbr\u003e\n\u003ca href=\"\/en-us\/products\/2026-07-27\"\u003eShow extra notes like \"+$100\" or \"made to order\" on variant options\u003c\/a\u003e\u003c\/p\u003e\n","brand":"STORE DOJO","offers":[{"title":"Default Title","offer_id":49231577088251,"sku":null,"price":0.0,"currency_code":"USD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0733\/0381\/8491\/files\/2026-08-28.png?v=1787883571","url":"https:\/\/store-dojo.com\/en-us\/products\/2026-08-28","provider":"STORE DOJO","version":"1.0","type":"link"}