WordPressElementorJetSmartFiltersCSSJavaScript

How to Fully Style a Native Browser Dropdown on WordPress & Elementor (JetSmartFilters)

Create a fully custom select that still behaves like a native one.

Milan PavlákMilan Pavlák
7 min čítania
How to Fully Style a Native Browser Dropdown on WordPress & Elementor (JetSmartFilters)

By default, HTML <select> elements come with their own browser styling. On a modern Elementor website, that usually means:

  • inconsistent look between Chrome, Safari, Firefox
  • limited control over the arrow, border radius, and spacing
  • a dropdown that simply doesn't match the rest of your UI

If you're using JetSmartFilters, many of your filters are built on top of <select>. Functionality is fine, but visually it often looks like an old default form element dropped into a clean design.

A common "fix" is to hide the select and replace it with completely custom HTML. But if that custom UI isn't properly synced with the original <select>, you can easily break:

  • filter logic
  • auto-submit behavior
  • integrations with other plugins

In this guide, we'll use a cleaner approach that:

  • keeps the original <select> in place as the single source of truth
  • hides only the native browser UI
  • renders a fully stylable custom dropdown on top
  • stays compatible with JetSmartFilters (including auto-submit)

Let's go step by step. 👇


What We're Building: A Custom Styled Select Dropdown for WordPress & Elementor

The idea is simple:

  1. Hide the native <select class="jet-select__control">.
  2. Use its wrapper .jet-select as the container for our custom UI.
  3. Create a custom "button" that shows the currently selected label.
  4. Generate a dropdown list from the original <option> elements.
  5. When a user clicks an item:
    • update the underlying <select>
    • update the visible label
    • highlight the selected item
    • dispatch a change event
  6. If you rely on JetSmartFilters auto-submit, keep that behavior working.

The result:

👀 looks like a modern custom component 🧠 behaves like a native <select>


Step 1 — Add the CSS to Style the Native Select Dropdown in WordPress

The CSS below is intentionally neutral:

  • no CSS custom properties
  • no Elementor global tokens
  • no project-specific fonts or SVGs
  • everything is copy–paste friendly

You can place it in:

  • Appearance → Customize → Additional CSS, or
  • Elementor Site Settings → Custom CSS, or
  • your child theme stylesheet.
/* Hide native select control */
select.jet-select__control {
  display: none !important;
}

/* Wrapper positioning (JetSmartFilters select wrapper) */
.jet-smart-filters-select,
.jet-select {
  position: relative;
  /* width locked in JS */
  min-width: 160px;
}

/* Hide the native apply-filters button */
.apply-filters {
  display: none !important;
}

/* — Closed "button" — */
.jet-select .select-selected {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  box-sizing: border-box;

  /* neutral, reusable typography */
  font-family: sans-serif;
  font-size: 16px;
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1.4;

  background: transparent;
  border: none;
  box-shadow: none;
  border-radius: 8px;
  padding: 12px 40px 12px 24px;
  cursor: pointer;
  user-select: none;
}

/* Custom arrow icon (SVG placeholder) */
.jet-select .select-selected::after {
  content: "";
  position: absolute;
  right: 16px;
  top: 50%;
  transform: translateY(-50%);
  width: 12px;
  height: 12px;
  background-image: url("YOUR-ARROW-ICON-SVG-URL-HERE.svg"); /* replace with your SVG icon URL */
  background-repeat: no-repeat;
  background-size: contain;
  background-position: center;
  pointer-events: none;
}

/* Rounded corners when open */
.jet-select .select-selected.select-arrow-active {
  border-radius: 8px 8px 0 0;
}

/* — Dropdown menu — */
.jet-select .select-items {
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
  z-index: 9999;

  background-color: #ffffff;
  border: 1px solid #d1d5db;
  border-radius: 16px;
  box-shadow: rgba(0, 0, 0, 0.12) 0px 7px 29px 0px;

  /* allow full expansion */
  max-height: none;
  overflow: visible;

  /* layout items centered with gap */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 24px 4px;
  box-sizing: border-box;
}

/* Hide when JS applies .select-hide */
.jet-select .select-items.select-hide {
  display: none !important;
}

/* Each dropdown item */
.jet-select .select-items div {
  display: inline-block;
  white-space: nowrap;

  font-family: sans-serif;
  font-size: 24px;
  font-weight: 700;
  text-transform: uppercase;
  line-height: 24px;
  color: #111827;

  background-color: #ffffff;
  padding: 4px 24px;
  cursor: pointer;
  user-select: none;
  text-align: center;
  transition: background-color 0.3s, color 0.3s;
  border-radius: 100px;
}

/* Hover & selected state */
.jet-select .select-items div:hover,
.jet-select .select-items .same-as-selected {
  background-color: #f3f4f6;
  color: #111827;
}

/* Utility class from JS (backup) */
.select-hide {
  display: none !important;
}

/* Existing filters-group layout */
.jet-filters-group {
  display: flex;
  flex-direction: row;
  gap: 16px;
  margin: 0 !important;
}

.jet-filter {
  margin: 0 !important;
}

/* Responsive tweaks */
@media (max-width: 767px) {
  .jet-filter {
    width: 100%;
  }
  .jet-filters-group {
    gap: 8px;
  }
}

This already gives you a neutral, clean, modern dropdown look. If you want to brand it later, you can simply update the colors, font, and border radius.


Step 2 — Add JavaScript to Build the Custom Dropdown UI (JetSmartFilters Compatible)

The script below:

  • finds all .jet-select wrappers
  • ensures there is a default "Any" option (or uses data-default-label)
  • creates a visible "button" based on the current selected option
  • builds a dropdown list from the <option> elements
  • keeps the underlying <select> in sync
  • triggers JetSmartFilters auto-submit by clicking .apply-filters__button

Add it via an HTML widget in the same template as your filters, or enqueue it globally via your theme.

<script>
document.addEventListener('DOMContentLoaded', function() {
  var selects = document.getElementsByClassName("jet-select");

  Array.prototype.forEach.call(selects, function(wrapper) {
    var sel = wrapper.getElementsByTagName("select")[0];
    if (!sel) return;

    // Ensure a default empty option at the top
    if (!Array.prototype.some.call(sel.options, function(o) { return o.value === ""; })) {
      var emptyOpt = document.createElement("option");
      emptyOpt.value = "";
      emptyOpt.textContent = sel.getAttribute("data-default-label") || "Any";
      sel.insertBefore(emptyOpt, sel.firstChild);
      sel.selectedIndex = 0;
    }

    // Create the visible selected DIV
    var selectedDiv = document.createElement("DIV");
    selectedDiv.className = "select-selected";
    selectedDiv.innerHTML = sel.options[sel.selectedIndex].innerHTML || (sel.getAttribute("data-default-label") || "Any");
    wrapper.appendChild(selectedDiv);

    // Optionally lock wrapper width based on initial content
    var rect = selectedDiv.getBoundingClientRect();
    if (rect.width) {
      wrapper.style.width = rect.width + "px";
    }

    // Build dropdown menu
    var listDiv = document.createElement("DIV");
    listDiv.className = "select-items select-hide";

    Array.prototype.forEach.call(sel.options, function(opt) {
      var item = document.createElement("DIV");
      item.innerHTML = opt.innerHTML;

      item.addEventListener("click", function() {
        var selectElement = wrapper.querySelector("select");
        var display = wrapper.querySelector(".select-selected");
        var options = selectElement.options;

        Array.prototype.forEach.call(options, function(o, idx) {
          if (o.innerHTML === item.innerHTML) {
            selectElement.selectedIndex = idx;
            display.innerHTML = item.innerHTML;

            // highlight selected item in the custom list
            listDiv.querySelectorAll(".same-as-selected").forEach(function(el) {
              el.classList.remove("same-as-selected");
            });
            item.classList.add("same-as-selected");

            // Trigger change so JetSmartFilters can react
            selectElement.dispatchEvent(new Event('change'));
          }
        });

        // Close dropdown after selection
        display.click();
      });

      listDiv.appendChild(item);
    });

    wrapper.appendChild(listDiv);

    // Toggle dropdown on click
    selectedDiv.addEventListener("click", function(e) {
      e.stopPropagation();
      closeAllSelect(this);
      this.nextSibling.classList.toggle("select-hide");
      this.classList.toggle("select-arrow-active");
    });
  });

  function closeAllSelect(current) {
    var lists = document.querySelectorAll(".jet-select .select-items");
    var selected = document.querySelectorAll(".jet-select .select-selected");

    lists.forEach(function(list, idx) {
      if (selected[idx] !== current) {
        list.classList.add("select-hide");
      }
    });

    selected.forEach(function(el) {
      if (el !== current) {
        el.classList.remove("select-arrow-active");
      }
    });
  }

  // Close all dropdowns when clicking outside
  document.addEventListener("click", function() {
    closeAllSelect(null);
  });

  // JetSmartFilters auto-submit logic
  document.querySelectorAll('.jet-select__control').forEach(function(sel) {
    sel.addEventListener('change', function() {
      var btn = document.querySelector('.apply-filters__button');
      if (btn) btn.click();
    });
  });
});
</script>

Where to Insert the Custom Select Code in Elementor or WordPress

You have two main options:

1. Inside the template that contains JetSmartFilters Add an HTML widget (for example at the bottom of the page or template) and paste:

  • the <style>…</style> block, and
  • the <script>…</script> block

This keeps everything scoped to that specific layout.

2. Globally via your theme or a code snippets plugin If you use the same styled dropdown across multiple templates, it can make sense to:

  • enqueue a global CSS file with the styles, and
  • enqueue a global JS file with the script.

As long as the HTML structure follows the JetSmartFilters pattern (.jet-select wrapper + .jet-select__control select inside), the script will pick it up.


Final Thoughts on Styling Native Select Fields in WordPress

Instead of fighting the browser's default select styling or fully replacing the field with a custom component, this approach gives you the best of both worlds:

  • the native <select> remains the single source of truth
  • JetSmartFilters and other plugins can still rely on it
  • the user sees a fully custom, modern dropdown that matches your design system

You end up with a dropdown that is:

✔ visually consistent with your Elementor design ✔ compatible with JetSmartFilters (including auto-submit) ✔ easy to reuse on future projects (no project-specific values)

If you want to adapt this further, you can:

  • tweak the colors, typography and radius in the CSS
  • add simple animations to the dropdown opening
  • extend the logic with keyboard navigation for even better accessibility

Let's Connect

Ready to discuss your project? Reach out through any of these channels.

Based in Bratislava, Slovakia. Available for projects worldwide.

Slovenská verzia stránky sa stále pripravuje a jej obsah nie je 100%

How to Fully Style a Native Browser Dropdown on WordPress & Elementor (JetSmartFilters)