Formerly Bootstrap TouchSpin — Now a modern ESM-first monorepo
TouchSpin (formerly Bootstrap TouchSpin) is a modern rewrite of the popular spinner component. The v5 line ships as an ESM-first monorepo with framework-specific packages so you can pick the delivery mode that fits your stack—core logic, renderer bundles, a jQuery bridge, or a Web Component.
TouchSpin v5 represents nearly 1,000 hours of development work — a complete ground-up rewrite to bring modern ESM architecture, tree-shaking, and multi-framework support to this popular component.
⭐ Become a Sponsor to help sustain ongoing development, faster bug fixes, and new features.
Your sponsorship keeps this project:
- ✅ Free and open-source for everyone
- 🚀 Actively maintained with regular updates
- 🐛 Well-tested with comprehensive test coverage
- 📚 Well-documented with migration guides
Every contribution, no matter the size, makes a real difference!
| Package | Purpose | Primary Entry | Bundled Assets |
|---|---|---|---|
@touchspin/core |
Framework-agnostic logic + renderer contracts | dist/index.js (ESM) |
Declarations only |
@touchspin/standalone |
Standalone mount API (core + renderer) | dist/index.js (ESM) |
Per-renderer subpaths (dist/bootstrapX.js) |
@touchspin/jquery |
Drop-in jQuery wrapper | dist/index.js (ESM) |
dist/umd/jquery.touchspin-*.umd.js globals |
@touchspin/webcomponent |
<touchspin-input> custom element |
Per-renderer subpaths | dist/umd/*.touchspin.umd.js globals |
@touchspin/renderer-bootstrap3 |
Bootstrap 3 renderer + CSS | dist/index.js (ESM) |
dist/touchspin-bootstrap3.css |
@touchspin/renderer-bootstrap4 |
Bootstrap 4 renderer + CSS | dist/index.js (ESM) |
dist/touchspin-bootstrap4.css |
@touchspin/renderer-bootstrap5 |
Bootstrap 5 renderer + CSS | dist/index.js (ESM) |
dist/touchspin-bootstrap5.css |
@touchspin/renderer-tailwind |
Tailwind-friendly renderer | dist/index.js (ESM) |
dist/touchspin-tailwind.css |
@touchspin/renderer-vanilla |
Framework-free renderer + theme | dist/index.js (ESM) |
dist/touchspin-vanilla.css, dist/themes/vanilla.css |
All packages declare "type": "module", target Node 22 (the configuration used for builds), and include licenses in the published tarballs. Renderer packages list their CSS under files and expose the stylesheet via exports."./css".
Framework-specific adapters are maintained in separate repositories with native tooling:
-
@touchspin/react (v5.0.1-alpha.0)
- Repository: https://github.com/istvan-ujjmeszaros/touchspin-react
- Installation:
npm install @touchspin/react@alpha @touchspin/core@alpha - Per-renderer subpath imports with controlled/uncontrolled patterns
-
@touchspin/angular (v5.0.1-alpha.0)
- Repository: https://github.com/istvan-ujjmeszaros/touchspin-angular
- Installation:
npm install @touchspin/angular@alpha @touchspin/core@alpha - ControlValueAccessor integration with Angular forms
-
@touchspin/vue (v5.1.0)
- Repository: https://github.com/istvan-ujjmeszaros/touchspin-vue
- Installation:
npm install @touchspin/vue @touchspin/core - Per-renderer subpath imports with v-model support
-
@touchspin/svelte (v5.0.0)
- Repository: https://github.com/istvan-ujjmeszaros/touchspin-svelte
- Installation:
npm install @touchspin/svelte @touchspin/core - Svelte 5 Runes support with bind:value directive
These adapters are independently versioned to match core compatibility. React and Angular are currently in alpha while Vue and Svelte are stable.
The simplest way to use TouchSpin with a mount API:
npm install @touchspin/standaloneimport { mount } from '@touchspin/standalone/bootstrap5';
const api = mount('#quantity', {
min: 0,
max: 100,
step: 1,
cancelable: true // Enable cancelable change events
});
// Listen to events
const input = document.querySelector('#quantity');
input.addEventListener('change:start', (event) => {
// Prevent change if needed
if (someCondition) {
event.preventDefault();
}
});
input.addEventListener('speedchange', (event) => {
console.log('Speed changed to:', event.detail.speed);
});Browser via CDN (ESM):
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@touchspin/renderer-bootstrap5@5/dist/touchspin-bootstrap5.css">
<script type="module">
import { mount } from 'https://cdn.jsdelivr.net/npm/@touchspin/standalone@5/dist/bootstrap5.js';
mount('#quantity', { min: 0, max: 100 });
</script>For advanced use with direct core access:
npm install @touchspin/core @touchspin/renderer-bootstrap5import { TouchSpin } from '@touchspin/core';
import Bootstrap5Renderer from '@touchspin/renderer-bootstrap5';
import '@touchspin/renderer-bootstrap5/css';
const input = document.querySelector('#quantity');
TouchSpin(input, {
renderer: Bootstrap5Renderer,
min: 0,
max: 100,
step: 1,
cancelable: true // Enable cancelable change events
});
// Listen to events
input.addEventListener('change:start', (event) => {
// Can prevent the change
event.preventDefault();
});npm install @touchspin/jquery jqueryUMD (Browser):
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@touchspin/jquery@5/dist/umd/jquery.touchspin-bootstrap5.umd.js"></script>
<script>
// Canonical (recommended)
$('#quantity').touchspin({ min: 0, max: 100 });
// Legacy alias (still supported)
$('#quantity').TouchSpin({ min: 0, max: 100 });
</script>ESM:
import { autoInstall } from '@touchspin/jquery';
import { mount } from '@touchspin/standalone/bootstrap5';
import $ from 'jquery';
autoInstall(mount);
$('#quantity').touchspin({ min: 0, max: 100 });npm install @touchspin/webcomponentimport '@touchspin/webcomponent/bootstrap5';<touchspin-input min="0" max="100" value="42"></touchspin-input>npm install @touchspin/react react react-domControlled:
import { useState } from 'react';
import TouchSpin from '@touchspin/react/bootstrap5';
function App() {
const [value, setValue] = useState(50);
return <TouchSpin value={value} onChange={setValue} min={0} max={100} />;
}Uncontrolled:
import TouchSpin from '@touchspin/react/vanilla';
<TouchSpin defaultValue={25} onChange={(val) => console.log(val)} />Imperative API:
import { useRef } from 'react';
import TouchSpin from '@touchspin/react/tailwind';
import type { TouchSpinHandle } from '@touchspin/react/tailwind';
const ref = useRef<TouchSpinHandle>(null);
<TouchSpin ref={ref} defaultValue={10} />
ref.current?.increment();Per-renderer imports: bootstrap3, bootstrap4, bootstrap5, tailwind, vanilla
SSR-safe: Works with Next.js, Remix, and other React frameworks
Example app: touchspin-react-example
See the @touchspin/react repository for complete API documentation.
npm install @touchspin/angular @angular/core @angular/common @angular/formsTemplate-driven forms:
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TouchSpinBootstrap5Component } from '@touchspin/angular/bootstrap5';
@Component({
selector: 'app-example',
standalone: true,
imports: [FormsModule, TouchSpinBootstrap5Component],
template: `
<touch-spin
[(ngModel)]="quantity"
[min]="0"
[max]="100"
[step]="1"
></touch-spin>
`
})
export class ExampleComponent {
quantity = 50;
}Reactive forms:
import { Component } from '@angular/core';
import { ReactiveFormsModule, FormControl } from '@angular/forms';
import { TouchSpinBootstrap5Component } from '@touchspin/angular/bootstrap5';
@Component({
selector: 'app-example',
standalone: true,
imports: [ReactiveFormsModule, TouchSpinBootstrap5Component],
template: `<touch-spin [formControl]="amountControl"></touch-spin>`
})
export class ExampleComponent {
amountControl = new FormControl(50);
}Imperative API:
import { Component, ViewChild } from '@angular/core';
import { TouchSpinBootstrap5Component, TouchSpinHandle } from '@touchspin/angular/bootstrap5';
@Component({
selector: 'app-example',
standalone: true,
imports: [TouchSpinBootstrap5Component],
template: `<touch-spin #spinner [(ngModel)]="value"></touch-spin>`
})
export class ExampleComponent {
@ViewChild('spinner') spinner?: TouchSpinHandle;
value = 0;
increment() {
this.spinner?.increment();
}
}Per-renderer imports: bootstrap3, bootstrap4, bootstrap5, tailwind, vanilla
ControlValueAccessor: Full integration with Angular forms
SSR-safe: Compatible with Angular Universal
See the @touchspin/angular repository for complete API documentation.
All CDN-facing entry points are catalogued in docs/cdn-assets.md. Remember that most packages are ESM-only; only the jQuery and Web Component adapters surface UMD globals.
For native ESM in the browser, supply an import map:
<script type="importmap">
{
"imports": {
"@touchspin/core": "https://cdn.jsdelivr.net/npm/@touchspin/core@5/dist/index.js",
"@touchspin/renderer-bootstrap5": "https://cdn.jsdelivr.net/npm/@touchspin/renderer-bootstrap5@5/dist/index.js"
}
}
</script>- Bootstrap projects: pick the renderer matching your Bootstrap major and include Bootstrap + Popper according to Bootstrap’s own peer dependencies.
- Headless/vanilla apps: use
@touchspin/renderer-vanillafor a lightweight, framework-free theme. - Utility-first CSS:
@touchspin/renderer-tailwindships a Tailwind-flavoured stylesheet you can scope or customize.
All renderers attach data-touchspin-injected attributes so the core can wire events without relying on framework-specific selectors.
| Tag | Intended audience | Notes |
|---|---|---|
alpha |
packaging in flux | Current default while we stabilize exports and docs. |
beta |
freeze candidate | Set once packaging + docs are finalized. |
next |
rolling canary | Use for CI smoke tests and early adopters. |
latest |
production | Published only after graduating from beta. |
Publishing is orchestrated through Changesets and the GitHub Actions workflow in .github/workflows/release.yml. See docs/releasing.md for the release playbook, dist-tag promotion policy, and provenance requirements.
Moving from the legacy [email protected] package? Start with the concise MIGRATION.md and consult deeper architectural notes in docs/architecture/migration-guide.md if you need step-by-step coverage of custom renderers or event differences.
- Start with the workspace overview in
AGENTS.mdfor cross-repo structure and expectations. - Read CONTRIBUTING.md for workspace guidelines, required build steps, and Changesets usage.
- Packaging or security concerns? Follow the disclosure process in SECURITY.md.
- Dev server, scripts, and architecture references remain in the
/docstree for contributors—see docs/index.md for a full sitemap.
TouchSpin is MIT-licensed. Every published package carries its own LICENSE file generated from the project’s root license.