«A modern, lightweight, highly customizable replacement for Select2.»
Forge Select is a next-generation JavaScript select component built for modern web applications. It provides a clean API, powerful customization options, excellent performance, and accessibility while remaining framework-agnostic.
Select2 has served the community well for many years, but modern web development has evolved.
Forge Select is designed to provide:
- 🚀 High performance
- 🎨 Fully customizable UI
- 📱 Responsive and mobile-friendly
- ♿ Accessibility (ARIA) support
- 🔍 Fast searching
- 🌳 Nested option groups
- 🏷️ Single & multiple selection
- 🧩 Plugin architecture
- 🌐 AJAX & remote data loading
- 🌙 Dark mode support
- 🌍 Internationalization (i18n)
- 📦 Zero dependency
Browse the documentation website at https://forgeselect.konexforge.com/docs/, or read the sources in docs/:
- API Reference — constructor, options, methods, events
- Examples — copy-pasteable snippets for every feature and framework
- Playground — live demo
- Migration from Select2 — option/event/method mapping and a migration checklist
- Benchmarks — reproducible bundle, initialization, search, and scrolling baseline
- Plugin Development Guide — write and register your own plugins
- Single Select
- Multiple Select
- Searchable Dropdown
- Async Data Source (AJAX with debounce, optional infinite-scroll pagination)
- Rich Item Rendering (avatar + label + description, XSS-safe built-in fields)
- Virtual Scrolling (automatic for large lists, with per-option render caching)
- Custom Templates
- Tags Mode (create options from free text)
- Keyboard Navigation
- Disabled Options
- Option Groups
- Tree Select (nested options with expand/collapse and cascading multi-select)
- Drag & Drop Tag Ordering (reorder a multi-select's selected tags by mouse/touch/pen, or Alt+Left/Alt+Right on keyboard)
- Clear Selection
- Placeholder
- Custom Themes (CSS variables, dark mode included)
- Event System
- Plugin Architecture
- Internationalization (en/vi built in, custom string tables)
- TypeScript Support (written in strict TypeScript, ships
.d.ts)
Planned/in-progress capabilities — Angular/Svelte wrappers — are tracked in the Roadmap below and intentionally not listed above as shipped features.
npm install forge-select
# or
yarn add forge-select
# or
pnpm add forge-select<select id="country">
<option value="vn">Vietnam</option>
<option value="jp">Japan</option>
<option value="us">United States</option>
</select>import ForgeSelect from "forge-select";
import "forge-select/styles.css";
new ForgeSelect("#country");const select = new ForgeSelect("#country", {
placeholder: "Select a country",
searchable: true,
multiple: false,
clearable: true,
allowCreate: false,
theme: "default",
});See the API Reference for all options, including data, ajax, templateResult, templateSelection, virtualScroll, language, and plugins.
select.on("change", (value) => console.log(value));
select.on("open", () => {});
select.on("close", () => {});
select.on("search", (query) => console.log("searching:", query));
select.on("clear", () => {});
select.on("error", (error) => console.error(error));Unsubscribe with select.off(event, handler).
Use select.setValue(value, { emitChange: false }) to synchronize external controlled state without emitting change.
new ForgeSelect("#users", {
ajax: {
url: (query) => `/api/users?q=${encodeURIComponent(query)}`,
debounce: 300,
transform: (response) => response.items.map((u) => ({ value: u.id, label: u.name })),
},
});More copy-pasteable snippets (multi-select, tags, custom templates, virtual scrolling, React/Vue/Svelte) are in docs/examples.md.
Write and run Forge Select code in the browser at https://forgeselect.konexforge.com/playground/ — with presets for every major feature. A curated feature showcase also lives at https://forgeselect.konexforge.com/demo/. See docs/playground.md for details and local setup.
| Option | Type | Default | Description |
|---|---|---|---|
placeholder |
string |
"" |
Text shown when nothing is selected |
searchable |
boolean |
true |
Show a search input in the dropdown |
multiple |
boolean |
false |
Allow selecting more than one option |
clearable |
boolean |
false |
Show a button to clear the current selection |
allowCreate |
boolean |
false |
Let the user create a new option from free text |
sortable |
boolean |
false |
Multi-select: let the user reorder selected tags |
closeOnSelect |
boolean |
false |
Multi-select: close the dropdown after each pick |
maxSelections |
number |
undefined |
Multi-select: caps the number of selected values |
theme |
string |
"default" |
Named theme applied to the control |
required |
boolean |
false |
Native form validation on a <select> mount |
data |
Array<Option | OptionGroup> |
undefined |
Static options, used instead of <option> children |
ajax |
AjaxConfig |
undefined |
Remote data source config |
filterOption |
(option, query) => boolean |
undefined |
Custom match predicate for search filtering |
minSearchLength |
number |
0 |
Minimum query length before filtering/ajax runs |
minResultsForSearch |
number |
0 |
Hide local search below an option-count threshold |
isOptionDisabled |
(option) => boolean |
undefined |
Dynamically disable an option per render |
virtualScroll |
boolean |
(auto) | Virtualize the list once it exceeds ~100 rows |
itemHeight |
number | "auto" |
36 |
Fixed or measured variable-height virtual rows |
language |
string | Record<string, string> |
"en" |
Locale code or a custom string table for i18n |
plugins |
Array<ForgeSelectPlugin> |
[] |
Plugins to register on this instance |
openOnFocus |
boolean |
false |
Open the dropdown on keyboard focus |
dropdownParent |
HTMLElement | string |
undefined |
Portal container for overflow-constrained layouts |
Full constructor signature, all options, instance methods, and events are documented in docs/api-reference.md.
Styling is driven entirely by CSS custom properties, and a dark theme ships out of the box:
new ForgeSelect("#country", { theme: "dark" });.forge-select {
--fs-border-focus: #e11d48;
--fs-radius: 4px;
}Forge Select is vanilla TypeScript/JavaScript, so it can be mounted inside any framework today. Official wrapper packages exist for a couple of them:
- Vanilla JavaScript
- React — via
forge-select-react(ForgeSelectReactcomponent, controlledvalue/onChange) - Vue — via
forge-select-vue(ForgeSelectVuecomponent,v-modelsupport) - Angular — mount manually for now; a dedicated wrapper is on the Roadmap
- Svelte — mount manually for now; a dedicated wrapper is on the Roadmap
- Next.js
- Nuxt
- Astro
- Chrome
- Edge
- Firefox
- Safari
- Mobile Browsers
Forge Select is designed as a drop-in-concept replacement for Select2: no jQuery dependency, native accessibility, and a smaller API surface. A full option/event/method mapping table and a step-by-step migration checklist are available in docs/migration-from-select2.md.
Run npm run bench for a reproducible JSON baseline covering bundle size, initialization, 10,000-option search latency, and virtual-scroll performance. The methodology and result fields are documented in docs/benchmarks.md.
- Tree Select
- Virtualized List
- Async Pagination
- Drag & Drop Ordering
- Theme Builder
- CSS Variables
- React Component
- Vue Component
- Angular Component
- Svelte Component
Forge Select uses a small plugin architecture (onInit, onOpen, onClose, onDestroy lifecycle hooks) so behavior can be extended without forking the core. See docs/plugin-development.md for the plugin interface and a complete example plugin.
npm install # install dev dependencies
npm test # run the vitest + jsdom test suite
npm run typecheck # strict TypeScript check
npm run build # build ESM + CJS + type declarations into dist/Source lives in src/, styles in styles/forge-select.css, and tests in tests/.
Contributions are welcome! See CONTRIBUTING.md for the development setup, project layout, and PR guidelines. Release history lives in CHANGELOG.md, and security reports should follow SECURITY.md. This project follows a Code of Conduct; by participating you agree to abide by its terms.
Built with ❤️ by KonexForge.