WooCommerce's default dropdown selectors for variable products work, but they're not exactly inspiring. For stores selling items like body jewelry with multiple attributes (gauge, size, material), dropdowns create friction. We built Variably Pretty to solve this with an elegant, modern approach.
The Problem: Dropdown Fatigue
Traditional WooCommerce variable product selection looks like this:
- Hidden Options: Customers must click to see what's available
- Multiple Clicks: Each attribute requires opening a dropdown
- Poor Mobile UX: Dropdowns are clunky on touchscreens
- No Visual Feedback: Can't see all options at once
- Confusing Availability: Customers don't know which combinations work until they try
For a body jewelry store, imagine someone trying to buy a hinge ring. They need to select gauge AND size. With dropdowns, they might pick 18g, then open the size dropdown only to find their preferred 8mm isn't available for that gauge. Frustrating!
Our Solution: Pill-Style Selectors
Variably Pretty replaces dropdowns with clickable "pills" - rounded buttons that display all options at once. When you select one attribute, incompatible options in other attributes automatically gray out.
Visual Clarity
All options visible at once - no hidden menus
Smart Availability
Incompatible options gray out automatically
Touch-Friendly
Large, tappable targets for mobile users
Native Integration
Works seamlessly with WooCommerce's variation system
Core Architecture
The plugin consists of three main components:
1. PHP Backend (Plugin Core)
The main plugin file hooks into WooCommerce's variation rendering system:
class Variably_Pretty {
public function __construct() {
// Replace dropdown HTML with pill HTML
add_filter(
'woocommerce_dropdown_variation_attribute_options_html',
[$this, 'render_pill_variations'],
10,
2
);
// Enqueue frontend assets
add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts']);
// Admin settings
add_action('admin_menu', [$this, 'add_admin_menu']);
}
}
2. Pill Rendering
Instead of returning a <select> element, we generate pill buttons:
public function render_pill_variations($html, $args) {
if (!$this->is_enabled_for_product($product->get_id())) {
return $html; // Use default dropdowns if not enabled
}
$pill_html = '<div class="variably-pretty-wrapper">';
$pill_html .= '<div class="variably-pretty-label">' . $attribute_label . '</div>';
foreach ($options as $option) {
$pill_html .= sprintf(
'<button class="variably-pretty-pill" data-value="%s">%s</button>',
esc_attr($option),
esc_html($option)
);
}
// Hidden select for WooCommerce compatibility
$pill_html .= '<select class="variably-pretty-hidden-select" style="display:none;">';
// ... options ...
$pill_html .= '</select>';
return $pill_html;
}
Key insight: We keep a hidden <select> element to maintain compatibility with WooCommerce's JavaScript. When a pill is clicked, we update the hidden select and trigger WooCommerce's change event.
3. JavaScript Interaction Logic
The JavaScript handles pill clicks and availability updates:
class VariablyPretty {
setupPillClicks() {
$('.variably-pretty-pill').on('click', function() {
const $pill = $(this);
const $wrapper = $pill.closest('.variably-pretty-wrapper');
const $hiddenSelect = $wrapper.find('.variably-pretty-hidden-select');
// Deselect others in same group
$wrapper.find('.variably-pretty-pill').removeClass('selected');
// Select this pill
$pill.addClass('selected');
$hiddenSelect.val($pill.data('value')).trigger('change');
// Update availability
this.updateAvailability();
});
}
}
Smart Availability Logic
The most complex part is determining which options should be grayed out. Here's how it works:
Getting Variation Data
WooCommerce stores variation data in JavaScript:
const variationData = this.form.data('product_variations');
// Example data structure:
// [
// {
// attributes: { attribute_gauge: "18g", attribute_size: "6mm" },
// is_in_stock: true,
// variation_id: 123
// },
// ...
// ]
Checking Option Availability
For each pill, we check if any variation exists that matches the current selections plus this option:
function isOptionAvailable(attrName, optionValue, currentSelections, variations) {
// Build test selections with this option
const testSelections = {...currentSelections, [attrName]: optionValue};
// Check if any variation matches
for (const variation of variations) {
if (!variation.is_in_stock) continue;
let matches = true;
for (const [key, value] of Object.entries(testSelections)) {
const varAttrKey = 'attribute_' + key;
const varAttrValue = variation.attributes[varAttrKey];
// Variation attribute is "" (any) or matches our value
if (varAttrValue !== '' && varAttrValue !== value) {
matches = false;
break;
}
}
if (matches) return true;
}
return false; // No matching variations found
}
Example Scenario
Let's say we have these variations available:
- 18g + 6mm
- 18g + 7mm
- 16g + 6mm
- 16g + 8mm
When the customer selects 18g:
- Plugin checks which sizes work with 18g
- Finds 6mm and 7mm are available
- Grays out 8mm (only works with 16g)
CSS Styling
The visual design uses modern CSS with smooth transitions:
.variably-pretty-pill {
padding: 10px 20px;
border: 2px solid #ddd;
border-radius: 25px;
background: #fff;
cursor: pointer;
transition: all 0.2s ease;
}
.variably-pretty-pill:hover:not(.disabled) {
border-color: #666;
transform: translateY(-2px);
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.variably-pretty-pill.selected {
background: #000;
color: #fff;
border-color: #000;
}
.variably-pretty-pill.disabled {
opacity: 0.3;
cursor: not-allowed;
pointer-events: none;
}
Admin Configuration
Store owners need control over which products use pill-style variations. We added a settings page under WooCommerce:
public function settings_page() {
$variable_products = wc_get_products([
'type' => 'variable',
'limit' => -1
]);
echo '<form method="post">';
echo '<label>';
echo '<input type="checkbox" name="enable_all" />';
echo 'Enable for all variable products';
echo '</label>';
foreach ($variable_products as $product) {
echo '<label>';
echo '<input type="checkbox" name="enabled_products[]" value="' . $product->get_id() . '" />';
echo $product->get_name();
echo '</label>';
}
echo '</form>';
}
Mobile Responsiveness
Pills automatically wrap and adjust size for smaller screens:
.variably-pretty-pills {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
@media (max-width: 768px) {
.variably-pretty-pill {
padding: 8px 16px;
font-size: 13px;
}
}
Technical Challenges
Challenge 1: WooCommerce Integration
Problem: WooCommerce expects <select> elements for its variation logic.
Solution: Keep hidden selects and sync them with pill selections. This maintains full compatibility with WooCommerce's cart, pricing, and stock systems.
Challenge 2: Performance with Many Variations
Problem: Products with 5+ attributes and 100+ variations could slow down availability checks.
Solution: Cache variation checks and only recalculate when selections change. Use efficient JavaScript with early returns.
Challenge 3: Theme Compatibility
Problem: Different themes structure variation forms differently.
Solution: Hook into WooCommerce's official filter instead of manipulating DOM. This works with any theme that follows WooCommerce standards.
Real-World Impact
For a body jewelry store selling hinge rings:
- Reduced Selection Time: Customers see all options immediately
- Fewer Cart Abandonments: No confusion about which combinations work
- Better Mobile Experience: Touch-friendly pills vs tiny dropdowns
- Increased Conversions: Clearer path to purchase
๐ก Pro Tip
Use clear, concise attribute names. "18g" is better than "18 gauge (1.0mm)" in pills. Put technical details in product descriptions instead.
Future Enhancements
Potential improvements for v2.0:
- Image Swatches: Show color/pattern pills with actual images
- Price Display: Show price changes on hover
- Stock Indicators: Visual badges for low stock
- Keyboard Navigation: Arrow keys to select options
- Animation Options: Configurable transition effects
Conclusion
Variably Pretty proves that small UX improvements can have big impacts. By replacing dropdowns with pills and adding smart availability logic, we created a more intuitive shopping experience that works seamlessly with WooCommerce.
The plugin is free, open-source, and ready to use on any WooCommerce store. Whether you're selling body jewelry, fashion, electronics, or any product with variations, Variably Pretty makes selection beautiful and effortless.
๐ฆ Download Variably Pretty
Ready to transform your variable products? Download the plugin and try it on your store!
Complete Code Structure
variably-pretty/
โโโ variably-pretty-plugin.php # Main plugin file (280 lines)
โโโ assets/
โ โโโ style.css # Pill styling
โ โโโ script.js # Interaction logic
โโโ README.md # Documentation
The entire plugin is just ~280 lines of well-structured PHP and JavaScript. Sometimes the best solutions are the simplest ones.