Skip to main content

How to Replace the Search Radius Dropdown with a Slider

Turn the Search Radius dropdown into a visual slider with tick labels, active highlighting, and a filled track.

RP Promap Help Article

How to Replace the Search Radius Dropdown with a Slider

This guide explains how to convert the RP Promap Search Radius dropdown into a visual slider with tick labels, active highlighting, and a filled track.

What this customization does

This script changes the default Search Radius dropdown into a slider.

For example, instead of showing:

100
200
300
No Limit

as a dropdown, customers will see a slider with labeled tick points.

The original dropdown is still used behind the scenes, so RP Promap continues to receive the selected radius value normally.

Where to install the script

Add the script to the page where RP Promap is embedded.

Recommended locations:

Shopify theme β†’ Online Store β†’ Themes β†’ Edit code

Then place the script in one of these locations:

theme.liquid

before the closing:

</body>

Or place it directly on the page/template where RP Promap is displayed.

Installation steps

  1. Open your Shopify theme editor.

  2. Go to the page or theme file where RP Promap loads.

  3. Paste the full script before the closing </body> tag.

  4. Save the file.

  5. Open the storefront page with RP Promap.

  6. Confirm the Search Radius dropdown is replaced by a slider.

Required HTML selectors

This script is designed for the RP Promap / Store Locator structure that uses:

#scasl-app-container

for the locator container, and:

#scasl-radius-container

for the Search Radius dropdown.

The script also waits for displayed results using:

.beside-scasl-item

How the script works

The script uses a MutationObserver to wait until RP Promap has finished rendering on the page.

It checks that:

The locator container exists
The radius dropdown exists
The dropdown has options
Store results are displayed

Once those conditions are true, it converts the dropdown into a slider and disconnects the observer.

This prevents the script from continuously watching the page and avoids performance issues.

Troubleshooting

Open your browser console and run:

rpSliderDebug.isReady()

If it returns:

true

RP Promap is ready.

You can manually retry the conversion with:

rpSliderDebug.run()

To confirm the dropdown exists:

rpSliderDebug.getSelect()

If this returns null, the selector may need to be updated.

Customization

To change the active slider color, update:

const ACTIVE_COLOR = "#111";

To change the inactive track color, update:

const INACTIVE_COLOR = "#d1d1d1";

To adjust the slider handle size, update:

const THUMB_SIZE = 18;

To adjust the track height, update:

const TRACK_HEIGHT = 6;

Notes

This script hides the original dropdown visually, but keeps it in the DOM. That allows RP Promap to continue using the existing radius field normally.

To Install the script copy it from here:

<script>
/**
* RP Promap / Store Locator Radius Slider
* ---------------------------------------
* Converts the Search Radius dropdown into a styled range slider.
*
* Features:
* - Waits until the store locator app is loaded
* - Waits until search results are displayed
* - Converts #scasl-radius-container into a slider
* - Adds tick dots and tick labels
* - Highlights the active tick
* - Shows an active value label under the thumb
* - Colors the slider track up to the selected value
* - Disconnects the MutationObserver after successful setup
*
* Target dropdown:
* <select id="scasl-radius-container">
*
* Debug helpers available in console:
* rpSliderDebug.run()
* rpSliderDebug.isReady()
* rpSliderDebug.getSelect()
*/

(function () {
/**
* =========================
* CONFIGURATION
* =========================
*/

const CONTAINER_SELECTOR = "#scasl-app-container";
const DROPDOWN_SELECTOR = "#scasl-radius-container";
const RESULTS_SELECTOR = ".beside-scasl-item";

const WRAPPER_CLASS = "rp-slider-wrapper";
const VALUE_LABEL_CLASS = "rp-slider-value-label";
const TICKS_CLASS = "rp-slider-ticks";
const TICK_CLASS = "rp-slider-tick";
const TICK_DOT_CLASS = "rp-slider-tick-dot";
const TICK_TEXT_CLASS = "rp-slider-tick-text";
const TICK_ACTIVE_CLASS = "is-active";

const ACTIVE_COLOR = "#111";
const INACTIVE_COLOR = "#d1d1d1";
const TRACK_HEIGHT = 6;
const THUMB_SIZE = 18;

let observer = null;
let hasConverted = false;

/**
* Adds all required CSS once.
*/
function injectStyles() {
if (document.getElementById("rp-slider-styles")) return;

const style = document.createElement("style");
style.id = "rp-slider-styles";
style.textContent = `
.${WRAPPER_CLASS} {
width: 100%;
margin-top: 10px;
position: relative;
}

.${WRAPPER_CLASS} input[type="range"] {
width: 100%;
margin: 0;
appearance: none;
height: ${THUMB_SIZE}px;
background: transparent;
cursor: pointer;
}

.${WRAPPER_CLASS} input[type="range"]::-webkit-slider-runnable-track {
height: ${TRACK_HEIGHT}px;
border-radius: 999px;
background: var(--rp-slider-track);
}

.${WRAPPER_CLASS} input[type="range"]::-webkit-slider-thumb {
appearance: none;
width: ${THUMB_SIZE}px;
height: ${THUMB_SIZE}px;
border-radius: 50%;
background: ${ACTIVE_COLOR};
margin-top: -${(THUMB_SIZE - TRACK_HEIGHT) / 2}px;
}

.${WRAPPER_CLASS} input[type="range"]::-moz-range-track {
height: ${TRACK_HEIGHT}px;
border-radius: 999px;
background: var(--rp-slider-track);
}

.${WRAPPER_CLASS} input[type="range"]::-moz-range-thumb {
width: ${THUMB_SIZE}px;
height: ${THUMB_SIZE}px;
border: 0;
border-radius: 50%;
background: ${ACTIVE_COLOR};
}

.${TICKS_CLASS} {
position: relative;
height: 28px;
margin-top: 4px;
}

.${TICK_CLASS} {
position: absolute;
top: 0;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
font-size: 11px;
color: #888;
white-space: nowrap;
}

.${TICK_DOT_CLASS} {
width: 7px;
height: 7px;
border-radius: 999px;
background: #bbb;
margin-bottom: 4px;
transition: transform 160ms ease, background 160ms ease;
}

.${TICK_CLASS}.${TICK_ACTIVE_CLASS} .${TICK_DOT_CLASS} {
background: ${ACTIVE_COLOR};
transform: scale(1.45);
}

.${TICK_CLASS}.${TICK_ACTIVE_CLASS} .${TICK_TEXT_CLASS} {
color: ${ACTIVE_COLOR};
font-weight: 700;
}

.${VALUE_LABEL_CLASS} {
position: relative;
display: inline-block;
margin-top: 8px;
font-size: 12px;
font-weight: 700;
transform: translateX(-50%);
white-space: nowrap;
transition: left 180ms ease;
will-change: left;
}
`;

document.head.appendChild(style);
}

function getSelect() {
return document.querySelector(DROPDOWN_SELECTOR);
}

/**
* Confirms that the locator app, radius dropdown,
* dropdown options, and displayed results are present.
*/
function isReady() {
const container = document.querySelector(CONTAINER_SELECTOR);
const select = getSelect();
const resultsCount = document.querySelectorAll(RESULTS_SELECTOR).length;

return container && select && select.options.length > 1 && resultsCount > 0;
}

/**
* Converts a dropdown index into a slider percentage.
*/
function getThumbCenterPercent(index, count) {
if (count <= 1) return 0;
return (index / (count - 1)) * 100;
}

/**
* Colors the slider track from left to selected value.
*/
function setTrackFill(slider, percent) {
slider.style.setProperty(
"--rp-slider-track",
`linear-gradient(to right, ${ACTIVE_COLOR} 0%, ${ACTIVE_COLOR} ${percent}%, ${INACTIVE_COLOR} ${percent}%, ${INACTIVE_COLOR} 100%)`
);
}

/**
* Creates dot ticks and text labels from the dropdown options.
*/
function createTicks(select) {
const ticks = document.createElement("div");
ticks.className = TICKS_CLASS;

const options = Array.from(select.options);
const count = options.length;

options.forEach(function (option, index) {
const tick = document.createElement("div");
tick.className = TICK_CLASS;
tick.style.left = getThumbCenterPercent(index, count) + "%";

const dot = document.createElement("div");
dot.className = TICK_DOT_CLASS;

const text = document.createElement("div");
text.className = TICK_TEXT_CLASS;
text.textContent = option.text;

tick.appendChild(dot);
tick.appendChild(text);
ticks.appendChild(tick);
});

return ticks;
}

/**
* Keeps slider, dropdown, active label, ticks,
* and track fill in sync.
*/
function updateUI(select, slider, label, ticks) {
const index = select.selectedIndex >= 0 ? select.selectedIndex : 0;
const count = select.options.length;
const percent = getThumbCenterPercent(index, count);

slider.value = String(index);
label.textContent = select.options[index]?.text || "";
label.style.left = percent + "%";

setTrackFill(slider, percent);

ticks.querySelectorAll("." + TICK_CLASS).forEach(function (tick, i) {
tick.classList.toggle(TICK_ACTIVE_CLASS, i === index);
});
}

/**
* Builds the slider UI and hides the original dropdown.
*/
function convert() {
if (hasConverted) return true;

const select = getSelect();
if (!select || select.options.length < 2) return false;

hasConverted = true;
injectStyles();

const wrapper = document.createElement("div");
wrapper.className = WRAPPER_CLASS;

const slider = document.createElement("input");
slider.type = "range";
slider.min = "0";
slider.max = String(select.options.length - 1);
slider.step = "1";

const ticks = createTicks(select);

const label = document.createElement("div");
label.className = VALUE_LABEL_CLASS;

slider.addEventListener("input", function () {
const index = Number(slider.value);

select.selectedIndex = index;
select.dispatchEvent(new Event("change", { bubbles: true }));

updateUI(select, slider, label, ticks);
});

select.addEventListener("change", function () {
updateUI(select, slider, label, ticks);
});

select.style.display = "none";
select.insertAdjacentElement("afterend", wrapper);

wrapper.appendChild(slider);
wrapper.appendChild(ticks);
wrapper.appendChild(label);

updateUI(select, slider, label, ticks);

return true;
}

/**
* Runs only when the app is ready.
*/
function run() {
if (!isReady()) return false;

const done = convert();

if (done && observer) {
observer.disconnect();
observer = null;
}

return done;
}

run();

/**
* Watches for delayed app rendering.
* Uses childList only to avoid page hangs from Google Maps updates.
*/
if (!hasConverted) {
observer = new MutationObserver(run);

observer.observe(document.body, {
childList: true,
subtree: true
});
}

window.rpSliderDebug = {
run,
isReady,
getSelect
};
})();
</script>

Β© Rose Perl Technology

Did this answer your question?