Products can be broken up into a maximum of three options, and a single combination of those options is a variant. For example, if a t-shirt comes in sizes `S`, `M`, and `L`, and colors `Black`, `White`, and `Red`, then `S/Black` would be a variant of that product. In this tutorial, you'll learn how to support product variants in your theme. ## Resources To support product variants, you'll use the following: - The [`product` object](/docs/api/liquid/objects/product) - The [`variant` object](/docs/api/liquid/objects/variant) ## Implementing product variants To support variants in your theme, you need to implement the following components: - [Variant deep link handling](#variant-deep-link-handling): A variant can be linked to directly, so you should ensure that the product information is updated for the "selected" variant when a variant is referenced in a product link. - [Variant selectors](#variant-selectors): You should build a variant selector to allow customers to easily browse the available variants of a product. Selecting a variant should update the page with variant-specific information. You might want to add these components to a section that can be included in a JSON product template, or a Liquid product template. ## Variant deep link handling Variant deep links are product links that contain a `?variant=[variant-id]` query parameter, where `[variant-id]` is the [ID](/docs/api/liquid/objects/variant#variant-id) of the associated variant. This allows you to link directly to a variant. You can add this functionality to a section that can be included in a JSON product template, or a Liquid product template. When variants are deep-linked, you can access which variant is linked through the `selected_variant` attribute of the [`product` object](/docs/api/liquid/objects/product#product-selected_variant). However, a product link won't always contain a deep-linked variant. In these cases, you can default to the selected, first available, or first variant through the `selected_or_first_available_variant` attribute. You can also deep link using the format `?option_values=[option-value-id-1],...,[option-value-id-N]` where `[option-value-id]` is the [ID](/docs/api/liquid/objects/product_option_value#product_option_value-id) of the associated option value. One option value ID must be provided per product option and the order must match the option order. If the option value combination maps to a variant that is not present, the requested option values will be selected but the product fields [`selected_variant`](/docs/api/liquid/objects/product#product-selected_variant) and [`selected_or_first_available_variant`](/docs/api/liquid/objects/product#product-selected_or_first_available_variant) will return null. After you identify the variant that you want to display, you need to ensure that the following product elements reflect it: - Product media - Product price - Variant selector ### Example The following example assigns a default variant using `product.selected_or_first_available_variant`, populates a basic media and price display based on that variant, and selects that variant in a basic variant selector. ```liquid {% assign current_variant = product.selected_or_first_available_variant %} <!-- Product media --> {% assign featured_media = current_variant.featured_media %} {% case featured_media.media_type %} {% when 'image' %} <div class="product-single__media" style="padding-top: {{ 1 | divided_by: featured_media.aspect_ratio | times: 100}}%;" data-media-id="{{ featured_media.id }}" > {{ featured_media | image_url: width: 2048 | image_tag }} </div> {% when 'external_video' %} <div class="product-single__media" style="padding-top: {{ 1 | divided_by: featured_media.aspect_ratio | times: 100}}%;" data-media-id="{{ featured_media.id }}" > {{ featured_media | external_video_tag }} </div> {% when 'video' %} <div class="product-single__media" data-media-id="{{ featured_media.id }}"> {{ featured_media | video_tag: controls: true }} </div> {% when 'model' %} <div class="product-single__media" style="padding-top: 100%" data-media-id="{{ featured_media.id }}" > {{ featured_media | model_viewer_tag }} </div> {% else %} <div class="product-single__media" style="padding-top: 100%;" data-media-id="{{ featured_media.id }}" > {{ featured_media | media_tag }} </div> {% endcase %} <!-- Product price --> <div class="price"> <span class="price-reg">{{ current_variant.price | money }}</span> {% if current_variant.compare_at_price > current_variant.price %} <span class="price-sale"><s>{{ current_variant.compare_at_price | money }}</s></span> {% endif %} </div> <!-- Variant selector --> <select name="id"> {% for variant in product.variants %} <option value="{{ variant.id }}" {% if variant == current_variant %}selected="selected"{% endif %} > {{ variant.title }} - {{ variant.price | money }} </option> {% endfor %} </select> ``` ## Variant selectors You can use a single variant selector where each option represents a variant. However, products may have more than one option. For a better buyer experience and to avoid future compatibility issues, we recommend that you present each of these options separately in the UI. To achieve this, you can use the [`product.options_with_values` object](/docs/api/liquid/objects/product#product-options_with_values) to generate a selector for each option. You can then use JavaScript to update the state when a new option value is selected. > Note: > Regardless of the approach you use for variant selection, you need to ensure that when a new variant is selected, the product media and price are updated to reflect the selected variant. Variant selectors should be added to a section that can be included in a JSON product template, or a Liquid product template. They can also be included in product grid or product quick view snippets to allow customers to view variants on other pages, like collections. > Tip: > Refer to the following files in Dawn for an example implementation: > > - [`product-variant-picker.liquid` section](https://github.com/Shopify/dawn/blob/main/snippets/product-variant-picker.liquid) > - [`global.js` asset](https://github.com/Shopify/dawn/blob/main/assets/global.js)