Skip to content

Instantly share code, notes, and snippets.

@joeybab3
Forked from trenkwill/component-facets.css
Last active May 30, 2024 21:58
Show Gist options
  • Save joeybab3/834b571e8fbbcb43861f2e331724973e to your computer and use it in GitHub Desktop.
Save joeybab3/834b571e8fbbcb43861f2e331724973e to your computer and use it in GitHub Desktop.
Shopify Dawn facets price range slider with 2 handles
// Add styling to the CSS file
.facets__price input[type='range'] {
-webkit-appearance: none;
padding: 0;
font: inherit;
outline: none;
color: rgb(var(--color-foreground));
opacity: .8;
background: rgb(var(--color-foreground));
box-sizing: border-box;
transition: opacity .2s;
cursor: pointer;
height: 1px;
}
.facets__price input[type='range']::-webkit-slider-thumb {
cursor: ew-resize;
background: rgb(var(--color-foreground));
color: rgb(var(--color-foreground));
height: 20px;
width: 20px;
border-radius: 50%;
cursor: pointer;
-webkit-appearance: none;
}
.facets__price input[type="range"]::-moz-range-progress {
background: rgb(var(--color-foreground));
}
.facets__price input[type="range"]::-moz-range-track {
background: rgb(var(--color-foreground));
}
/* IE*/
.facets__price input[type="range"]::-ms-fill-lower {
background: rgb(var(--color-foreground));
}
.facets__price input[type="range"]::-ms-fill-upper {
background: rgb(var(--color-foreground));
}
.facets__price .range-wrap {
position: relative;
margin: 0 auto 3rem;
}
.facets__price .range {
width: 100%;
}
.facets__price .bubble {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
// replace the PriceRange class in facets.js
class PriceRange extends HTMLElement {
constructor() {
super();
this.querySelectorAll('input')
.forEach(element => element.addEventListener('change', this.onRangeChange.bind(this, element.parentElement.querySelector('.bubble'))));
// commented out in order to make range sliders work properly
// this.setMinAndMaxValues();
this.querySelectorAll('.range-wrap').forEach(wrap => {
const range = wrap.querySelector(".range");
const bubble = wrap.querySelector(".bubble");
range.addEventListener("input", () => {
this.setBubble(range, bubble);
});
this.setBubble(range, bubble);
});
}
onRangeChange(event, bubble) {
this.adjustToValidValues(event.currentTarget);
this.setBubble(event.currentTarget, bubble);
// commented out in order to make range sliders work properly
// this.setMinAndMaxValues();
}
setBubble(range, bubble) {
const val = range.value;
const min = range.min ? range.min : 0;
const max = range.max ? range.max : 100;
const newVal = Number(((val - min) * 100) / (max - min));
bubble.innerHTML = val;
// Sorta magic numbers based on size of the native UI thumb
bubble.style.left = `calc(${newVal}% + (${8 - newVal * 0.15}px))`;
}
setMinAndMaxValues() {
const inputs = this.querySelectorAll('input');
const minInput = inputs[0];
const maxInput = inputs[1];
if (maxInput.value) minInput.setAttribute('max', maxInput.value);
if (minInput.value) maxInput.setAttribute('min', minInput.value);
if (minInput.value === '') maxInput.setAttribute('min', 0);
if (maxInput.value === '') minInput.setAttribute('max', maxInput.getAttribute('max'));
}
adjustToValidValues(input) {
const value = Number(input.value);
const min = Number(input.getAttribute('min'));
const max = Number(input.getAttribute('max'));
if (value < min) input.value = min;
if (value > max) input.value = max;
}
}
// replace the <price-range> element that contains number inputs with range inputs
<price-range class="facets__price">
<div class="range-wrap">
<input
class="range"
name="{{ filter.min_value.param_name }}"
id="Filter-{{ filter.label | escape }}-GTE"
{% if filter.min_value.value %}
value="
{%- if uses_comma_decimals -%}
{{ filter.min_value.value | money_without_currency | replace: '.', '' | replace: ',', '' }}
{% else %}
{{ filter.min_value.value | money_without_currency | replace: ',', '' }}
{% endif %}
"
{% else %}
value="0"
min="0"
step="0.5"
max="
{%- if uses_comma_decimals -%}
{{ filter.range_max | divided_by: 2 | money_without_currency | replace: '.', '' | replace: ',', '' }}
{% else %}
{{ filter.range_max | divided_by: 2 | money_without_currency | replace: ',', '' }}
{% endif %}
"
{% endif %}
type="range"
>
<output class="bubble"></output>
</div>
<div class="range-wrap">
<input
class="range"
name="{{ filter.max_value.param_name }}"
id="Filter-{{ filter.label | escape }}-LTE"
step="0.5"
{% if filter.max_value.value %}
value="
{%- if uses_comma_decimals -%}
{{ filter.max_value.value | money_without_currency | replace: '.', '' | replace: ',', '' }}
{% else %}
{{ filter.max_value.value | money_without_currency | replace: ',', '' }}
{% endif %}
"
{% else %}
value="{{ filter.range_max | money_without_currency | replace: ',', '' }}"
min="{{ filter.range_max | divided_by: 2 | money_without_currency | replace: ',', '' }}"
{% endif %}
value="{{ filter.max_value.value | money_without_currency | replace: ',', '' }}"
type="range"
max="{{ filter.range_max | money_without_currency | replace: ',', '' }}"
>
<output class="bubble"></output>
</div>
</price-range>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment