← Back to documentation
Introduction
Custom CSS allows you to fully customize the appearance of your variant image swatches.
You can change colors, sizes, spacing, fonts, and more to match your store's design.
The swatches render inside your theme's DOM, and the custom CSS you write is injected directly into the swatch stylesheet.
This means you can override any default style using the CSS variables listed below, or target specific elements with class selectors.
Getting started
All custom CSS should be wrapped in the :root, :host selector. Using both ensures compatibility whether the swatches render normally or inside a Shadow DOM (some themes use Shadow DOM for app blocks).
Try this example to create a clean, modern look:
:root, :host {
--rubik-swatch-image-border-radius: 50%;
--rubik-swatch-image-selected-border-color: #2563EB;
--rubik-swatch-image-border-color: #ddd;
--rubik-swatch-image-hover-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
--rubik-swatch-option-name-color: #111;
}
Want pill-style buttons with a dark selected state? Try this:
:root, :host {
--rubik-swatch-pill-border-radius: 20px;
--rubik-swatch-pill-selected-background: #111;
--rubik-swatch-pill-selected-color: #fff;
--rubik-swatch-pill-selected-border-color: #111;
--rubik-swatch-pill-padding: 10px 20px;
}
You can override any CSS variable listed below, or target specific elements for advanced customization.
CSS variables reference
Below is a complete reference of all CSS variables you can customize. Each variable controls a specific aspect of the swatch appearance.
Layout & spacing
| Variable |
Default |
Description |
--rubik-swatch-margin-top |
5px |
Top margin of the swatch container |
--rubik-swatch-margin-bottom |
5px |
Bottom margin of the swatch container |
--rubik-swatch-fieldset-margin-top |
10px |
Top margin between multiple option groups |
--rubik-swatch-gap |
8px |
Gap between individual swatches |
--rubik-swatch-margin |
0 |
Margin around the swatch items container |
--rubik-swatch-alignment |
flex-start |
Horizontal alignment: flex-start (left), center, flex-end (right) |
--rubik-swatch-text-align |
left |
Text alignment of the option label |
--rubik-swatch-transition-duration |
0.2s |
Duration of hover/transition animations |
Option labels
| Variable |
Default |
Description |
--rubik-swatch-option-font-size |
14px |
Font size of the option name (e.g., "Color: Blue") |
--rubik-swatch-option-name-color |
#333333 |
Text color of the option name |
--rubik-swatch-option-name-display |
table |
Display mode of the option name container |
--rubik-swatch-option-margin-bottom |
8px |
Bottom margin of the option fieldset |
--rubik-swatch-option-name-label-display |
inline |
Display mode of the option name label (e.g., "Color") |
--rubik-swatch-option-colon-display |
inline |
Display mode of the colon separator |
--rubik-swatch-option-name-value-display |
inline |
Display mode of the selected value (e.g., "Blue") |
Image swatches
| Variable |
Default |
Description |
--rubik-swatch-image-size |
70px |
Width (and default height) of image swatches |
--rubik-swatch-image-height |
var(--rubik-swatch-image-size) |
Height of image swatches (defaults to width for square) |
--rubik-swatch-image-border-width |
1px |
Border width of image swatches |
--rubik-swatch-image-border-color |
#e5e5e5 |
Border color of image swatches |
--rubik-swatch-image-border-radius |
0 |
Border radius (use 50% for circles) |
--rubik-swatch-image-aspect-ratio |
auto |
Aspect ratio of image swatches |
--rubik-swatch-image-background-color |
#ffffff |
Background color behind the image |
--rubik-swatch-image-object-fit |
contain |
How image fits: contain, cover, fill |
--rubik-swatch-image-hover-shadow |
0 2px 8px rgba(0, 0, 0, 0.15) |
Box shadow on hover |
--rubik-swatch-image-hover-scale |
1.1 |
Scale factor on hover (1 = no zoom) |
--rubik-swatch-image-selected-border-color |
#333 |
Border color when selected |
--rubik-swatch-image-selected-border-width |
1px |
Border width when selected |
--rubik-swatch-image-selected-outline |
none |
Outline when selected (e.g., "2px solid #000") |
--rubik-swatch-image-selected-outline-offset |
0 |
Offset of the selection outline |
Pill / text swatches
| Variable |
Default |
Description |
--rubik-swatch-pill-padding |
8px 16px |
Inner padding of pill swatches |
--rubik-swatch-pill-border-width |
1px |
Border width |
--rubik-swatch-pill-border-color |
#e5e5e5 |
Border color |
--rubik-swatch-pill-border-radius |
0 |
Border radius (use 20px+ for rounded pills) |
--rubik-swatch-pill-background |
#fff |
Background color |
--rubik-swatch-pill-color |
#333 |
Text color |
--rubik-swatch-pill-font-size |
14px |
Font size |
--rubik-swatch-pill-min-width |
50px |
Minimum width of pill swatches |
--rubik-swatch-pill-hover-shadow |
0 2px 8px rgba(0, 0, 0, 0.15) |
Box shadow on hover |
--rubik-swatch-pill-selected-background |
#333 |
Background color when selected |
--rubik-swatch-pill-selected-color |
#fff |
Text color when selected |
--rubik-swatch-pill-selected-border-color |
#333 |
Border color when selected |
--rubik-swatch-pill-selected-border-width |
1px |
Border width when selected |
--rubik-swatch-pill-selected-outline |
none |
Outline when selected |
--rubik-swatch-pill-selected-outline-offset |
0 |
Offset of the selection outline |
--rubik-swatch-pill-unavailable-opacity |
0.9 |
Opacity of unavailable pill swatches |
Text labels below images
| Variable |
Default |
Description |
--rubik-swatch-label-display |
none |
Set to block to show text labels below image swatches |
--rubik-swatch-label-background |
#f5f5f5 |
Background color of the label |
--rubik-swatch-label-border-color |
#e5e5e5 |
Border color of the label |
--rubik-swatch-label-color |
#333 |
Text color of the label |
--rubik-swatch-label-text-overflow |
ellipsis |
How overflowing text is handled |
--rubik-swatch-label-white-space |
nowrap |
Set to normal to allow wrapping |
Sold out / unavailable
| Variable |
Default |
Description |
--rubik-swatch-unavailable-line-color |
#666 |
Color of the diagonal strike-through line (general) |
--rubik-swatch-image-unavailable-line-color |
#666 |
Strike-through line color for image swatches |
--rubik-swatch-pill-unavailable-line-color |
#666 |
Strike-through line color for pill swatches |
Dropdown - base
| Variable |
Default |
Description |
--rubik-swatch-dropdown-min-width |
150px |
Minimum width of the dropdown |
--rubik-swatch-dropdown-max-width |
100% |
Maximum width of the dropdown |
--rubik-swatch-dropdown-padding |
10px 40px 10px 16px |
Inner padding (right side larger for arrow) |
--rubik-swatch-dropdown-font-size |
14px |
Font size |
--rubik-swatch-dropdown-font-family |
inherit |
Font family (inherits from theme) |
--rubik-swatch-dropdown-line-height |
1.5 |
Line height |
--rubik-swatch-dropdown-color |
#333 |
Text color |
--rubik-swatch-dropdown-background |
#fff |
Background color |
--rubik-swatch-dropdown-arrow |
url(...svg) |
Custom arrow icon (SVG data URL) |
--rubik-swatch-dropdown-border-width |
1px |
Border width |
--rubik-swatch-dropdown-border-color |
#e5e5e5 |
Border color |
--rubik-swatch-dropdown-border-radius |
0 |
Border radius |
--rubik-swatch-dropdown-transition |
0.2s |
Transition duration |
--rubik-swatch-dropdown-shadow |
none |
Box shadow |
Dropdown - hover
| Variable |
Default |
Description |
--rubik-swatch-dropdown-hover-border-color |
#ccc |
Border color on hover |
--rubik-swatch-dropdown-hover-shadow |
0 2px 8px rgba(0, 0, 0, 0.1) |
Box shadow on hover |
Dropdown - focus
| Variable |
Default |
Description |
--rubik-swatch-dropdown-focus-outline |
2px solid #333 |
Outline when focused |
--rubik-swatch-dropdown-focus-outline-offset |
2px |
Offset of the focus outline |
--rubik-swatch-dropdown-focus-border-color |
#333 |
Border color when focused |
--rubik-swatch-dropdown-focus-shadow |
0 0 0 3px rgba(0, 0, 0, 0.05) |
Box shadow when focused |
Dropdown - disabled
| Variable |
Default |
Description |
--rubik-swatch-dropdown-disabled-opacity |
0.6 |
Opacity when disabled |
--rubik-swatch-dropdown-disabled-background |
#f5f5f5 |
Background color when disabled |
Dropdown - options
| Variable |
Default |
Description |
--rubik-swatch-dropdown-option-padding |
8px |
Padding of dropdown options |
--rubik-swatch-dropdown-option-color |
inherit |
Text color of options |
--rubik-swatch-dropdown-option-background |
#fff |
Background color of options |
--rubik-swatch-dropdown-option-disabled-color |
#999 |
Text color of disabled options |
--rubik-swatch-dropdown-option-disabled-style |
italic |
Font style of disabled options |
--rubik-swatch-dropdown-option-selected-background |
#f0f0f0 |
Background color of the selected option |
--rubik-swatch-dropdown-option-selected-weight |
600 |
Font weight of the selected option |
Dropdown - mobile
| Variable |
Default |
Description |
--rubik-swatch-dropdown-mobile-font-size |
16px |
Font size on mobile (larger for touch targets) |
--rubik-swatch-dropdown-mobile-padding |
12px 40px 12px 16px |
Padding on mobile (larger for touch targets) |
Tooltip
| Variable |
Default |
Description |
--rubik-swatch-tooltip-background |
rgba(0, 0, 0, 0.9) |
Background color |
--rubik-swatch-tooltip-color |
#fff |
Text color |
--rubik-swatch-tooltip-font-size |
12px |
Font size |
--rubik-swatch-tooltip-line-height |
1.4 |
Line height |
--rubik-swatch-tooltip-padding |
6px 12px |
Inner padding |
--rubik-swatch-tooltip-border-radius |
4px |
Border radius |
--rubik-swatch-tooltip-offset |
8px |
Distance from the swatch element |
--rubik-swatch-tooltip-shadow |
0 2px 8px rgba(0, 0, 0, 0.15) |
Box shadow |
--rubik-swatch-tooltip-arrow-size |
5px |
Size of the tooltip arrow |
--rubik-swatch-tooltip-transition-duration |
0.2s |
Fade in/out duration |
--rubik-swatch-tooltip-z-index |
1000 |
Z-index stacking order |
Size chart
| Variable |
Default |
Description |
--rubik-swatch-size-chart-margin-left |
10px |
Left margin of the size chart link |
--rubik-swatch-size-chart-color |
inherit |
Text color of the size chart link |
--rubik-swatch-size-chart-text-decoration |
underline |
Text decoration of the size chart link |
HTML structure
Understanding the DOM structure helps with advanced customization. Here's the complete HTML hierarchy the app generates:
Image swatch structure
<div class="rubik-swatch">
<fieldset class="rubik-swatch__option">
<legend class="rubik-swatch__option-name">
<span class="rubik-swatch__option-label">
<span class="rubik-swatch__option-name-label">Color</span>
<span class="rubik-swatch__option-colon">: </span>
<span class="rubik-swatch__option-name-value">Blue</span>
</span>
<span class="rubik-swatch__size-chart-placeholder"></span>
</legend>
<div class="rubik-swatch__items">
<div class="rubik-swatch__item-wrapper">
<input type="radio" class="rubik-swatch__input" id="..." name="..." value="..." checked>
<label class="rubik-swatch__label rubik-swatch__label--image" for="...">
<img class="rubik-swatch__image" src="..." alt="Blue">
</label>
<span class="rubik-swatch__text-label">Blue</span>
<div class="rubik-swatch__tooltip">Blue</div>
</div>
</div>
</fieldset>
</div>
Pill swatch structure
<div class="rubik-swatch__item-wrapper">
<input type="radio" class="rubik-swatch__input" id="..." name="..." value="...">
<label class="rubik-swatch__label rubik-swatch__label--pill" for="...">
Small
</label>
</div>
Dropdown structure
<div class="rubik-swatch">
<fieldset class="rubik-swatch__option">
<legend class="rubik-swatch__option-name">...</legend>
<select class="rubik-swatch__dropdown">
<option value="small">Small</option>
<option value="medium" selected>Medium</option>
<option value="large">Large</option>
<option value="xl" disabled>XL (Sold out)</option>
</select>
</fieldset>
</div>
Unavailable swatch structure
<!-- Image swatch with unavailable overlay -->
<label class="rubik-swatch__label rubik-swatch__label--image rubik-swatch__label--unavailable" for="...">
<img class="rubik-swatch__image" src="..." alt="Red">
<svg class="rubik-swatch__unavailable-overlay">
<line x1="0" y1="100%" x2="100%" y2="0" stroke="currentColor" stroke-width="1.5" />
</svg>
</label>
<!-- Pill swatch with unavailable overlay -->
<label class="rubik-swatch__label rubik-swatch__label--pill rubik-swatch__label--unavailable" for="...">
XL
<svg class="rubik-swatch__unavailable-overlay">
<line x1="0" y1="100%" x2="100%" y2="0" stroke="currentColor" stroke-width="1.5" />
</svg>
</label>
HTML class reference
For advanced customization, you can target specific elements using CSS classes.
Use these selectors inside your :root, :host block.
Container classes
| Class |
Description |
.rubik-swatch |
Main swatch container |
.rubik-swatch__option |
Fieldset wrapping one option group |
.rubik-swatch__option-name |
Legend element with option label (e.g., "Color: Blue") |
.rubik-swatch__items |
Flex container holding all swatch items |
.rubik-swatch__item-wrapper |
Wrapper around each individual swatch (input + label + tooltip) |
Label classes
| Selector |
Description |
.rubik-swatch__option-name-label |
The option name text (e.g., "Color") |
.rubik-swatch__option-colon |
The colon separator ": " |
.rubik-swatch__option-name-value |
The selected value text (e.g., "Blue") |
Swatch type classes
| Class |
Description |
.rubik-swatch__label |
Base class for all swatch labels |
.rubik-swatch__label--image |
Image swatch variant |
.rubik-swatch__label--pill |
Pill/text swatch variant |
.rubik-swatch__label--unavailable |
Sold-out/unavailable swatch |
Element classes
| Class |
Description |
.rubik-swatch__input |
Hidden radio input |
.rubik-swatch__image |
Image element inside image swatch |
.rubik-swatch__text-label |
Text label below image swatch |
.rubik-swatch__tooltip |
Tooltip element |
.rubik-swatch__unavailable-overlay |
SVG strike-through overlay for sold-out swatches |
.rubik-swatch__dropdown |
Dropdown select element |
.rubik-swatch__size-chart-placeholder |
Size chart link placeholder |
State selectors
| Selector |
Description |
.rubik-swatch__input:checked + .rubik-swatch__label |
Currently selected swatch |
.rubik-swatch__input:disabled + .rubik-swatch__label |
Disabled swatch |
.rubik-swatch__label:hover |
Swatch on hover |
Examples
Rounded image swatches
:root, :host {
--rubik-swatch-image-border-radius: 50%;
--rubik-swatch-image-size: 50px;
--rubik-swatch-image-object-fit: cover;
}
Pill swatch styling
:root, :host {
/* Rounded pills */
--rubik-swatch-pill-border-radius: 20px;
--rubik-swatch-pill-padding: 10px 24px;
/* Custom colors */
--rubik-swatch-pill-background: #f8f8f8;
--rubik-swatch-pill-color: #222;
--rubik-swatch-pill-border-color: #ddd;
/* Selected state */
--rubik-swatch-pill-selected-background: #222;
--rubik-swatch-pill-selected-color: #fff;
--rubik-swatch-pill-selected-border-color: #222;
}
Show text labels below images
:root, :host {
--rubik-swatch-label-display: block;
--rubik-swatch-label-background: transparent;
--rubik-swatch-label-border-color: transparent;
--rubik-swatch-label-color: #555;
}
Center-align swatches
:root, :host {
--rubik-swatch-alignment: center;
--rubik-swatch-text-align: center;
}
Hide option label parts
/* Hide the option name entirely */
:root, :host {
--rubik-swatch-option-name-display: none;
}
/* Or hide just the selected value (keep "Color" but hide ": Blue") */
:root, :host {
--rubik-swatch-option-name-value-display: none;
--rubik-swatch-option-colon-display: none;
}
Dropdown styling
:root, :host {
--rubik-swatch-dropdown-border-radius: 8px;
--rubik-swatch-dropdown-border-color: #ccc;
--rubik-swatch-dropdown-focus-border-color: #2563EB;
--rubik-swatch-dropdown-focus-outline: 2px solid #2563EB;
--rubik-swatch-dropdown-padding: 12px 40px 12px 16px;
}
Remove hover effects
:root, :host {
--rubik-swatch-image-hover-shadow: none;
--rubik-swatch-image-hover-scale: 1;
--rubik-swatch-pill-hover-shadow: none;
--rubik-swatch-transition-duration: 0s;
}
Advanced: target specific elements
/* Make selected swatch label bold */
.rubik-swatch__input:checked + .rubik-swatch__label--image {
border-width: 2px;
border-color: #2563EB;
}
/* Style the option name */
.rubik-swatch__option-name {
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
}
/* Custom tooltip style */
:root, :host {
--rubik-swatch-tooltip-background: #2563EB;
--rubik-swatch-tooltip-color: #fff;
--rubik-swatch-tooltip-border-radius: 8px;
}
Quick reference
A compact list of all CSS variables with their default values, organized by category.
Copy variables from here and paste into your custom CSS.
Layout & spacing
--rubik-swatch-margin-top: 5px;
--rubik-swatch-margin-bottom: 5px;
--rubik-swatch-fieldset-margin-top: 10px;
--rubik-swatch-gap: 8px;
--rubik-swatch-margin: 0;
--rubik-swatch-alignment: flex-start;
--rubik-swatch-text-align: left;
--rubik-swatch-transition-duration: 0.2s;
Option labels
--rubik-swatch-option-font-size: 14px;
--rubik-swatch-option-name-color: #333333;
--rubik-swatch-option-name-display: table;
--rubik-swatch-option-margin-bottom: 8px;
--rubik-swatch-option-name-label-display: inline;
--rubik-swatch-option-colon-display: inline;
--rubik-swatch-option-name-value-display: inline;
Image swatches
--rubik-swatch-image-size: 70px;
--rubik-swatch-image-height: var(--rubik-swatch-image-size);
--rubik-swatch-image-border-width: 1px;
--rubik-swatch-image-border-color: #e5e5e5;
--rubik-swatch-image-border-radius: 0;
--rubik-swatch-image-aspect-ratio: auto;
--rubik-swatch-image-background-color: #ffffff;
--rubik-swatch-image-object-fit: contain;
--rubik-swatch-image-hover-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
--rubik-swatch-image-hover-scale: 1.1;
--rubik-swatch-image-selected-border-color: #333;
--rubik-swatch-image-selected-border-width: 1px;
--rubik-swatch-image-selected-outline: none;
--rubik-swatch-image-selected-outline-offset: 0;
Pill / text swatches
--rubik-swatch-pill-padding: 8px 16px;
--rubik-swatch-pill-border-width: 1px;
--rubik-swatch-pill-border-color: #e5e5e5;
--rubik-swatch-pill-border-radius: 0;
--rubik-swatch-pill-background: #fff;
--rubik-swatch-pill-color: #333;
--rubik-swatch-pill-font-size: 14px;
--rubik-swatch-pill-min-width: 50px;
--rubik-swatch-pill-hover-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
--rubik-swatch-pill-selected-background: #333;
--rubik-swatch-pill-selected-color: #fff;
--rubik-swatch-pill-selected-border-color: #333;
--rubik-swatch-pill-selected-border-width: 1px;
--rubik-swatch-pill-selected-outline: none;
--rubik-swatch-pill-selected-outline-offset: 0;
--rubik-swatch-pill-unavailable-opacity: 0.9;
Text labels
--rubik-swatch-label-display: none;
--rubik-swatch-label-background: #f5f5f5;
--rubik-swatch-label-border-color: #e5e5e5;
--rubik-swatch-label-color: #333;
--rubik-swatch-label-text-overflow: ellipsis;
--rubik-swatch-label-white-space: nowrap;
Sold out / unavailable
--rubik-swatch-unavailable-line-color: #666;
--rubik-swatch-image-unavailable-line-color: #666;
--rubik-swatch-pill-unavailable-line-color: #666;
Dropdown
--rubik-swatch-dropdown-min-width: 150px;
--rubik-swatch-dropdown-max-width: 100%;
--rubik-swatch-dropdown-padding: 10px 40px 10px 16px;
--rubik-swatch-dropdown-font-size: 14px;
--rubik-swatch-dropdown-font-family: inherit;
--rubik-swatch-dropdown-line-height: 1.5;
--rubik-swatch-dropdown-color: #333;
--rubik-swatch-dropdown-background: #fff;
--rubik-swatch-dropdown-border-width: 1px;
--rubik-swatch-dropdown-border-color: #e5e5e5;
--rubik-swatch-dropdown-border-radius: 0;
--rubik-swatch-dropdown-transition: 0.2s;
--rubik-swatch-dropdown-shadow: none;
/* Hover */
--rubik-swatch-dropdown-hover-border-color: #ccc;
--rubik-swatch-dropdown-hover-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
/* Focus */
--rubik-swatch-dropdown-focus-outline: 2px solid #333;
--rubik-swatch-dropdown-focus-outline-offset: 2px;
--rubik-swatch-dropdown-focus-border-color: #333;
--rubik-swatch-dropdown-focus-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05);
/* Disabled */
--rubik-swatch-dropdown-disabled-opacity: 0.6;
--rubik-swatch-dropdown-disabled-background: #f5f5f5;
/* Options */
--rubik-swatch-dropdown-option-padding: 8px;
--rubik-swatch-dropdown-option-color: inherit;
--rubik-swatch-dropdown-option-background: #fff;
--rubik-swatch-dropdown-option-disabled-color: #999;
--rubik-swatch-dropdown-option-disabled-style: italic;
--rubik-swatch-dropdown-option-selected-background: #f0f0f0;
--rubik-swatch-dropdown-option-selected-weight: 600;
/* Mobile */
--rubik-swatch-dropdown-mobile-font-size: 16px;
--rubik-swatch-dropdown-mobile-padding: 12px 40px 12px 16px;
Tooltip
--rubik-swatch-tooltip-background: rgba(0, 0, 0, 0.9);
--rubik-swatch-tooltip-color: #fff;
--rubik-swatch-tooltip-font-size: 12px;
--rubik-swatch-tooltip-line-height: 1.4;
--rubik-swatch-tooltip-padding: 6px 12px;
--rubik-swatch-tooltip-border-radius: 4px;
--rubik-swatch-tooltip-offset: 8px;
--rubik-swatch-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
--rubik-swatch-tooltip-arrow-size: 5px;
--rubik-swatch-tooltip-transition-duration: 0.2s;
--rubik-swatch-tooltip-z-index: 1000;
Size chart
--rubik-swatch-size-chart-margin-left: 10px;
--rubik-swatch-size-chart-color: inherit;
--rubik-swatch-size-chart-text-decoration: underline;
Tips & best practices
- Use
:root, :host as your wrapping selector. This ensures your styles work whether the swatches are rendered normally or inside a Shadow DOM.
- Prefer CSS variables over class selectors when possible. Variables are more reliable and won't break if internal HTML structure changes.
- Use browser dev tools to inspect the swatch elements. In Chrome, open DevTools, find the
.rubik-swatch element, and explore its children to see the live structure.
- 4000 character limit - the custom CSS field has a 4000 character limit. Keep your CSS concise and avoid unnecessary whitespace.
- Start simple - override one or two variables at a time to understand their effect before adding more.
- Test on both desktop and mobile - some variables have mobile-specific overrides (especially dropdown padding and font size).
- Check specificity - if your class-based styles aren't applying, you may need to increase specificity by chaining selectors.