aSelect

The aSelect plugin transforms traditional HTML <select> elements into enhanced dropdown controls that display options in a tabular (grid) format.

This provides a more visually rich and powerful selection experience, especially useful when options have multiple data attributes that need to be displayed clearly.

Grid dropdown Search Keyboard navigation Server-side Dependent fields
Key Features
  • Converts select elements into table-based dropdowns
  • Supports both client-side and server-side data
  • Pagination for large datasets
  • Search and filter functionality
  • Full keyboard navigation support
  • Maintains original select element behavior
  • Customizable events and callbacks
  • Responsive design
  • Dependent field support
  • Clear button option
  • Dynamic loading of server-side data

Why aSelect?

Built to solve real-world dropdown challenges that traditional select wrappers struggle with.

Structured, Tabular Data

Most select wrappers support search, but very few support a true tabular layout. Real-world selections often require more context than a single label.

aSelect allows you to display multiple columns—such as Customer Name, Address, and Phone—inside the dropdown itself, without custom popovers or repeated UI logic as your application grows.

Built for Massive Datasets

Dropdowns should not break when your data grows. Whether you have thousands or millions of records, aSelect handles it efficiently.

With server-side integration, pagination, and infinite scrolling, aSelect loads data on demand—keeping forms fast, responsive, and scalable.

Cleaner, Smarter UI

Forms often need additional actions—like adding a new customer when the desired option doesn’t exist.

Instead of cluttering the form with extra buttons near labels, aSelect lets you place contextual actions directly inside the dropdown, near the search—keeping the UI clean and intuitive.

Dependencies

jQuery

Core dependency used for DOM manipulation and events.

Popper.js

Handles dropdown positioning logic.

Bootstrap

Used for styling and tooltip support.

Installation

Include the required dependencies and the aSelect plugin after jQuery. You can use a CDN or host the files locally.

CDN Installation
Recommended

Quickest way to get started. Just copy and paste into your page.

<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB"
      crossorigin="anonymous">

<!-- jQuery (Required) -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"
        integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
        crossorigin="anonymous"></script>

<!-- Popper (Required) -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
        integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
        crossorigin="anonymous"></script>

<!-- Bootstrap JS (Core only — NOT bundle) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.min.js"
        integrity="sha384-G/EV+4j2dNv+tEPo3++6LCgdCROaejBqfUeNjuKAiuXbjrxilcCdDz6ZAVfHWe1Y"
        crossorigin="anonymous"></script>

<!-- aSelect -->
<link rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@amrit-maan/aselect/dist/aselect.min.css">
<script src="https://cdn.jsdelivr.net/npm/@amrit-maan/aselect/dist/aselect.umd.min.js"></script>
Local Installation (npm)

Install aSelect locally using npm and host the files yourself. Recommended for ASP.NET Core MVC and bundled environments.

1. Install via npm
npm install @amrit-maan/aselect
2. Copy files to wwwroot

Copy the required files from node_modules into your public assets folder.

node_modules/@amrit-maan/aselect/dist/
node_modules/jquery/dist/
node_modules/bootstrap/dist/
node_modules/@popperjs/core/dist/umd/
3. Reference in your layout
<!-- Dependencies -->
<script src="/lib/jquery/jquery.min.js"></script>

<link rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css">
<script src="/lib/popper/popper.min.js"></script>
<script src="/lib/bootstrap/js/bootstrap.min.js"></script>

<!-- aSelect plugin -->
<link rel="stylesheet" href="/lib/aselect/aselect.min.css">
<script src="/lib/aselect/aselect.umd.min.js"></script>
Important: Do NOT include bootstrap.bundle.min.js.
The bundle already contains Popper. aSelect requires Bootstrap core JS and Popper to be loaded separately.

Ensure jQuery is loaded before aSelect.

Basic Usage

Initialize aSelect on an existing <select> element to transform it into a searchable, keyboard-friendly dropdown.

Client-side data

Use this approach when all options are already available in the DOM.

<select id="mySelect">
                          <option value="1">Option 1</option>
                          <option value="2">Option 2</option>
                        </select>
$('#mySelect').aSelect();
Live Demo

This select below is transformed using the exact code shown on the left.

The original <select> remains in the DOM and continues to fire standard change events.

Table / Grid Layout

If you want a table-like dropdown, you can define additional columns using HTML data attributes and specify which fields should be displayed using data-headers.

With Data Attributes

Each option provides multiple attributes that are rendered as columns in the dropdown.

<select id="productSelect" data-headers="intId,nvcName,decPrice,intCategory">
                          <option value="1"
                                  data-intId="1"
                                  data-nvcName="Product A"
                                  data-decPrice="19.99"
                                  data-intCategory="Electronics">
                            Product A
                          </option>
                          <option value="2"
                                  data-intId="2"
                                    data-nvcName="Product B"
                                    data-decPrice="29.99"
                                    data-intCategory="Clothing">
                            Product B
                          </option>
                        </select>
$('#productSelect').aSelect();
Live Demo

The dropdown below displays each option in a grid format.

Column headers are generated from data-headers. The first camelCase segment (e.g. int, nvc, dec) is treated as a technical prefix and is not displayed. Header names use typed camelCase notation, where the first segment is a technical identifier (e.g. int, nvc, dec) and is not displayed. This allows headers to be reused for API field mapping and data type identification.

Multi-select

Use the native multiple attribute on the select. Selected values display as removable chips. Click chips to deselect.

HTML + JS

Add multiple attribute and initialize normally.

<select id="multiSelect" multiple>
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
  <option value="3">Option 3</option>
</select>

<script>
  $('#multiSelect').aSelect();
</script>
Live Demo

Select multiple values and see them appear as chips.

Selected values are stored in the original <select> element.

Server-side Data

For large datasets, load data from the server by providing a URL.

Note: The code below uses a C# ASP.NET Core backend implementation and is just a sample example.

Below is a structured approach showing how I handled server-side dropdown loading. Your implementation may vary.

I initially have:

Initialization Script

<script>
    function initializePlugins($context) {
        $context.find('select.aSelect').each(function () {
            $(this).aSelect(); // if aSelect is already initialized, aSelect ignores this.
        });
    }

    $(document).ready(function () {
        initializePlugins($(document));
    });

    // Run after every jQuery AJAX request completes
    $(document).ajaxComplete(function () {
        initializePlugins($(document));
    });
</script>
                

Now any code that contains aSelect will be initialized automatically. No need to manually call it every time. Next, we will utilize aSelect data-attributes to set up and fetch dropdown data.

Let’s define a DTO first:

Dropdown DTO

Define all dropdowns in a central place. Use a static class DropdownRepository to return DTO based on dropdown id.

Dropdown Repository

Add in server provider:

Service Registration

builder.Services.AddSingleton();
                

Now build an endpoint to serve dropdown data. Here is a controller example:

Common Controller

using DotNetMvc.DTOs;
using DotNetMvc.Repository;
using Microsoft.AspNetCore.Mvc;
namespace DotNetMvc.Controllers;

public class CommonController(DropdownRepository dropDownRepo) : Controller
{
    public async Task Dropdown(string id, string search, string start, string length, string valColumn, string selectedValue, bool onlyFetchSelectedRow, bool initialLoad, List headers, Dictionary dependsOn)
    {
        // Logic to handle dropdown data fetching using dropDownRepo
        List listAllDropdowns = dropDownRepo.GetAllDropdown();
        DropdownDTO dropdown = listAllDropdowns.First(x => x.chDropdownId == id);

        List> data = null; // TODO: Implement your logic. I am leaving this intentionally.. your should know how you should fetch your data.
        Dictionary selectedRow = null;

        if (onlyFetchSelectedRow)
        {
            if (string.IsNullOrEmpty(selectedValue))
            {
                throw new InvalidOperationException("Select value cannot be empty");
            }


            string sql = dropdown.nvcSqlQuery.Replace("{{filters}}", $"({dropdown.vcValColumn} = @valColumn)"); // this is okay as we in the backend control what is the dropdown.vcValColumn...

            var parameters = new Dictionary
            {
                { "@valColumn", selectedValue },
            };
            foreach (var kv in dependsOn)
            {
                parameters[kv.Key] = kv.Value;
            }
            selectedRow = null; // TODO: Implement your logic. I am leaving this intentionally.. your should know how you should fetch your data. This should be return if onlyFetchSelectedRow is true. This maybe a Db repo Call
        }
        else
        {
            data = null; // TODO: Implement your logic. I am leaving this intentionally.. your should know how you should fetch your data.  This maybe a Db repo Call
        }
        return Json(new { data, selectedRow, dropdown.vcValColumn, dropdown.vcTextColumn, dropdown.bitImplementPagination, dropdown.vcSkippedColumns });
    }
}

                
HTML

Add data-url to the select.


<select
    name="orders"
    class="form-select aSelect"
    data-url="/Common/Dropdown/Orders">
</select>
                        
Initialize

Initialize normally. The plugin will fetch rows from the endpoint.

$('.aSelect').aSelect();
Server response format
{
  "bitImplementPagination": true,
  "vcSkippedColumns": "id,category",
  "vcTextColumn": "name",
  "vcValColumn": "id",
  "data": [
    {"id": 1, "name": "Product A", "price": 19.99, "category": "Electronics"},
    {"id": 2, "name": "Product B", "price": 29.99, "category": "Clothing"}
  ]
}
Tip: Use vcSkippedColumns to hide fields you don’t want displayed as columns.

Configuration Options

Configure aSelect using JavaScript initialization options or HTML data attributes.

Initialization Options
$('#mySelect').aSelect({
  // Basic options
  id: 'custom-id',               // Custom ID for the instance
  placeHolder: 'Select...',      // Placeholder text
  showClearButton: true,         // Show clear button
  quickLinks: '<button>Add New</button>', // Custom HTML for quick links

  // Server-side options
  ajaxUrl: '/api/data',          // URL for server-side data
  headers: ['id', 'name'],       // Column headers

  // Callbacks
  onOpen: function() { console.log('Dropdown opened'); },
  onClose: function() { console.log('Dropdown closed'); },
  onChange: function(newValue) { console.log('Selected:', newValue); },

  // Dependent fields
  dependsOn: [
    { selector: '#divisionId', paramName: 'divisionId' }
  ],

  // AJAX payload
  getAjaxDefaultPayload: function() {
    return {
      userId: 123,
      token: 'abc123'
    };
  }
});
Special Note: getAjaxDefaultPayload

You may need this option when your server-side endpoint requires authentication, authorization, or additional contextual data (such as tenant, user, or security tokens).

Instead of defining the payload on every aSelect instance, you can configure it globally once after login. A common example is sending an Anti-Forgery token with every request.

$.fn.aSelect.defaults = {
    getAjaxDefaultPayload: function () {
        return {
            __RequestVerificationToken: getAntiForgeryToken()
        };
    }
};

A-Select Plugin Data Attributes

Configure the A-Select plugin directly through HTML data attributes for quick setup.

Data Attribute Description Usage Example
data-url Server-side

Endpoint URL for fetching data via AJAX (POST request)

<select data-url="/api/data"></select>
data-headers Server-side

Comma-separated list of column names to display in table view

<select data-headers="id,name,email,department"></select>
data-show-clear-button UI Feature

Show clear selection button ("true" or "false")

<select data-show-clear-button="true"></select>
data-quicklink UI Feature

CSS selector for HTML element to insert as quick links

<select data-quicklink="#quick-links"></select>
data-unique-by Validation

Comma-separated selectors to exclude already selected values

<select data-unique-by=".user-select"></select>
data-creatable UI Feature

Allow creating new entries from search input ("true" or "false")

<select data-creatable="true"></select>
data-depends-on Validation

JSON array of dependent fields that must be selected first

<select data-depends-on='[{"selector":"#country","param":"countryId"}]'></select>
data-hide-excluded Validation

Hide excluded rows when using unique-by ("true" or "false")

<select data-hide-excluded="true"></select>
multiple Core

Standard HTML attribute to enable multi-selection mode

<select multiple></select>
Complete Example
<select 
    class="form-select"
    data-url="/api/users"
    data-headers="id,name,email,role"
    data-show-clear-button="true"
    data-quicklink="#user-quick-links"
    data-unique-by=".user-selector"
    data-creatable="true"
    data-hide-excluded="true"
    data-depends-on='[{"selector":"#department","param":"deptId"}]'
    multiple
>
    <option value="">Select User</option>
</select>
Quick Links HTML
<div id="user-quick-links">
    <button type="button" 
            class="btn btn-sm btn-outline-primary" 
            data-value="active">
        Active Users
    </button>
    <button type="button" 
            class="btn btn-sm btn-outline-success" 
            data-value="admin">
        Administrators
    </button>
</div>
Usage Notes:
  • Attributes prefixed with data- are HTML5 compliant
  • Boolean attributes accept "true" or "false" string values
  • JSON format is required for data-depends-on attribute
  • Multiple attributes can be combined for complex functionality
  • Server-side attributes require proper AJAX endpoint implementation

Methods

Interact with aSelect via standard jQuery patterns.

Get / Set Value
// Get current value
const value = $('#mySelect').val();

// Set value
$('#mySelect').val('2');
Destroy / Refresh
// Remove the aSelect instance
$('#mySelect').aSelect('destroy');
// Refresh the instance
$('#mySelect').aSelect('refresh');

Events

aSelect maintains normal select behavior, so you can keep using standard jQuery events. It also exposes plugin-specific events.

Standard jQuery Events
$('#mySelect').on('change', function() {
  console.log('Selected value:', $(this).val());
});
Plugin-specific Events
$('#mySelect').on('aSelect:open', function() {
  console.log('Dropdown opened');
});
$('#mySelect').on('aSelect:close', function() {
                            console.log('Dropdown closed');
                        });

Advanced Usage

Common advanced patterns for dynamic forms.

Dependent Fields
$('#mySelect').aSelect({
  dependsOn: [
    { selector: '#country', paramName: 'countryId' },
    { selector: '#region', paramName: 'regionId' }
  ]
});
Custom AJAX Payload
$('#serverSelect').aSelect({
  getAjaxDefaultPayload: function() {
    return {
      department: 'sales',
      region: 'north'
    };
  }
});
Handling Disabled State
// Disable the select
$('#mySelect').prop('disabled', true);

// Enable the select
$('#mySelect').prop('disabled', false);

Keyboard Navigation

Supported keys:

Arrow Up / Down
Navigate through options
Enter
Select highlighted option
Escape
Close dropdown
Tab
Close dropdown and move to next element

Styling

The plugin adds CSS classes you can customize:

.a-select-wrapper
Main container
.a-select-display
Display element showing selected value
.a-select-dropdown
Dropdown container
.a-select-table-container
Scrollable table container
.a-select-table
The options table
.a-select-filter-container
Search/filter container
.a-select-clear-button
Clear button
.a-select-open
Added to wrapper when dropdown is open
.a-select-disabled
Added to wrapper when disabled

Browser Compatibility

The aSelect plugin supports all modern browsers and Internet Explorer 11+.

Supported Browsers
  • Chrome (latest)
  • Firefox (latest)
  • Edge
  • Safari
  • Internet Explorer 11+
IE11 Requirements

When using Internet Explorer 11, you may need to include polyfills for:

  • MutationObserver
  • Promise
For best performance and full feature support, modern evergreen browsers are recommended.