@Bengtsalez
I quickly threw something together for you using the Dawn theme version 2.4.0.
For that you are going to want to add a few files for theme consistency, something like this:
assets/component-product-form.css
Show More
css /* Dynamic checkout */ .shopify-payment-button__button { border-radius: 0; font-family: inherit; min-height: 4.6rem; } .shopify-payment-button__button [role="button"].focused, .no-js .shopify-payment-button__button [role="button"]:focus { outline: .2rem solid rgba(var(--color-foreground),.5) !important; outline-offset: 0.3rem; box-shadow: 0 0 0 .1rem rgba(var(--color-button),var(--alpha-button-border)),0 0 0 .3rem rgb(var(--color-background)),0 0 .5rem .4rem rgba(var(--color-foreground),.3) !important; } .shopify-payment-button__button [role="button"]:focus:not(:focus-visible) { outline: 0; box-shadow: none !important; } .shopify-payment-button__button [role="button"]:focus-visible { outline: .2rem solid rgba(var(--color-foreground),.5) !important; box-shadow: 0 0 0 .1rem rgba(var(--color-button),var(--alpha-button-border)),0 0 0 .3rem rgb(var(--color-background)),0 0 .5rem .4rem rgba(var(--color-foreground),.3) !important; } .shopify-payment-button__button--unbranded { background-color: rgba(var(--color-button), var(--alpha-button-background)); box-shadow: 0 0 0 0.1rem rgba(var(--color-button), var(--alpha-button-border)); color: rgb(var(--color-button-text)); font-size: 1.4rem; line-height: calc(1 + 0.2 / var(--font-body-scale)); letter-spacing: 0.07rem; } .shopify-payment-button__button--unbranded::selection { background-color: rgba(var(--color-button-text), 0.3); } .shopify-payment-button__button--unbranded:hover, .shopify-payment-button__button--unbranded:hover:not([disabled]) { background-color: rgba(var(--color-button), var(--alpha-button-background)); box-shadow: 0 0 0 0.2rem rgba(var(--color-button), var(--alpha-button-border)); } .shopify-payment-button__more-options { margin: 1.6rem 0 1rem; font-size: 1.2rem; line-height: calc(1 + 0.5 / var(--font-body-scale)); letter-spacing: 0.05rem; text-decoration: underline; text-underline-offset: 0.3rem; } .shopify-payment-button__button--hidden { display: none; } /* Product form */ .product-form { display: block; position: relative; z-index: 2; } .product-form__error-message-wrapper:not([hidden]) { display: flex; align-items: flex-start; font-size: 1.2rem; margin-bottom: 1.5rem; } .product-form__error-message-wrapper svg { flex-shrink: 0; width: 1.2rem; height: 1.2rem; margin-right: 0.7rem; margin-top: 0.5rem; } /* Form Elements */ .product-form__input { flex: 0 0 100%; padding: 0; margin: 0 0 1.2rem 0; max-width: 37rem; min-width: fit-content; border: none; } variant-radios, variant-selects { display: block; } .product-form__input--dropdown { margin-bottom: 1.6rem; } .product-form__input .form__label { padding-left: 0; } fieldset.product-form__input .form__label { margin-bottom: 0.2rem; } .product-form__input input[type='radio'] { clip: rect(0, 0, 0, 0); overflow: hidden; position: absolute; height: 1px; width: 1px; } .product-form__input input[type='radio'] + label { border: 0.1rem solid rgba(var(--color-foreground), 0.55); border-radius: 4rem; color: rgb(var(--color-foreground)); display: inline-block; margin: 0.7rem 0.5rem 0.2rem 0; padding: 1rem 2rem; font-size: 1.4rem; letter-spacing: 0.1rem; line-height: 1; text-align: center; transition: border var(--duration-short) ease; cursor: pointer; } .product-form__input input[type='radio'] + label:hover { border: 0.1rem solid rgb(var(--color-foreground)); } .product-form__input input[type='radio']:checked + label { background-color: rgb(var(--color-foreground)); color: rgb(var(--color-background)); } @media screen and (forced-colors: active) { .product-form__input input[type=radio]:checked + label { text-decoration: underline; } } .product-form__input input[type='radio']:checked + label::selection { background-color: rgba(var(--color-background), 0.3); } .product-form__input input[type='radio']:disabled + label { border-color: rgba(var(--color-foreground), 0.1); color: rgba(var(--color-foreground), 0.4); text-decoration: line-through; } .product-form__input input[type='radio']:focus-visible + label { box-shadow: 0 0 0 0.3rem rgb(var(--color-background)), 0 0 0 0.5rem rgba(var(--color-foreground), 0.55); } /* Fallback */ .product-form__input input[type='radio'].focused + label, .no-js .shopify-payment-button__button [role="button"]:focus + label { box-shadow: 0 0 0 0.3rem rgb(var(--color-background)), 0 0 0 0.5rem rgba(var(--color-foreground), 0.55); } /* No outline when focus-visible is available in the browser */ .no-js .product-form__input input[type='radio']:focus:not(:focus-visible) + label { box-shadow: none; } .product-form__input .select { max-width: 25rem; } .product-form__submit { margin-bottom: 1rem; } .no-js .product-form__submit.button--secondary { --color-button: var(--color-base-accent-1); --color-button-text: var(--color-base-solid-button-labels); --alpha-button-background: 1; } .product-form__submit[aria-disabled="true"] + .shopify-payment-button, .product-form__submit[disabled] + .shopify-payment-button { display: none; } @media screen and (forced-colors: active) { .product-form__submit[aria-disabled="true"] { color: Window; } } /* Overrides */ .shopify-payment-button__more-options { color: rgb(var(--color-foreground)); } .shopify-payment-button__button { font-size: 1.5rem; letter-spacing: 0.1rem; }
snippets/product-form.liquid
Show More
markup {{ 'component-product-form.css' | asset_url | stylesheet_tag }}
Then on the snippets/product-card.liquid you will want to include:
{%- liquid
if product_card_product.selling_plan_groups == empty
render 'product-form', product: product_card_product
endif
-%}
directly under the price rendering tag.
Ideally you would not load in the CSS and JS on every product card so you may want to move those to the collection section(s) and/or template so that they only load once per page. Not only that but the CSS and JS are the code as directly took from the theme, with the exception of moving the product form above the product card link in the stacking context, so they may include code unnecessary for the implementation.
Hope that helps!