
TabMate is a lightweight JavaScript library that enables proper tab indentation behavior for HTML textarea elements.
Features:
- Smart Tab Key Handling: Press Tab to insert configurable spaces or tabs at cursor position
- Shift+Tab Outdenting: Remove indentation using Shift+Tab, even across multiple selected lines
- Multi-line Indentation: Select text blocks and indent/outdent entire sections simultaneously
- Configurable Tab Width: Set custom indentation size from 2 to 100+ spaces per tab
- Framework Agnostic: Works with vanilla JavaScript, React, Vue, Angular, or any framework
- Zero Dependencies: Built with TypeScript, no external libraries required
- Tiny Bundle Size: Less than 1KB gzipped impact on your application
See it in action:
How to use it:
1. Install TabMate and import it into your Vanilla js, React, Vue, or Angular projects.
# Yarn $ yarn add @tabmate/core # NPM $ npm install @tabmate/core # PNPM $ pnpm install @tabmate/core
import { tabmate } from "@tabmate/core";2. Attach TabMate to any textarea element and done.
// Get a reference to your textarea
const textarea = document.querySelector("textarea");
// Attach TabMate
const instance = tabmate(textarea);3. For projects without a build step, the UMD version is available.
<script src="https://cdn.jsdelivr.net/npm/@tabmate/core/dist/tabmate.umd.min.js"></script>
<script>
const textarea = document.querySelector("textarea");
const instance = window.tabmate.tabmate(textarea);
</script>4. Customize indentation behavior with configuration options:
const instance = tabmate(textarea, {
tabs: 2, // Number of tab levels to indent
tabWidth: 4 // Spaces per tab level (default: 2)
});5. API methods.
instance.detach(): Removes the event listeners from the textarea.instance.getOptions(): Returns the current configuration object.instance.updateOptions(newOptions): Updates the TabMate instance with new options.
How It Works
When you call tabmate(textarea), the library attaches a keydown event listener to the element. This listener specifically watches for the Tab key.
When the Tab key is pressed, it calls event.preventDefault() to stop the browser’s default behavior of switching focus to the next interactive element. It then inspects the state of the textarea, including selectionStart, selectionEnd, and value.
- If no text is selected, it inserts a string of spaces (determined by the
tabWidthoption) at the cursor’s position. - If text is selected, the logic is a bit more involved. It identifies the start of the first selected line and the end of the last selected line. It then iterates through each line in the selection, adding a set of spaces to the beginning of each one.
- For
Shift+Tab, it performs the reverse operation, detecting and removing a set of spaces from the beginning of each selected line.
The library directly manipulates the textarea’s .value property and then carefully recalculates and sets .selectionStart and .selectionEnd to ensure the selection is preserved correctly after the indentation or outdentation occurs.
It’s a classic vanilla JavaScript approach to text manipulation within an input field, which is why it’s so lightweight and has no dependencies.
FAQs
Q: Can I use TabMate with a contenteditable div?
A: No, TabMate is designed specifically to work with <textarea> elements. Its logic relies on the value, selectionStart, and selectionEnd properties, which are not part of the contenteditable API.
Q: How can I dynamically change the tab size after initialization?
A: Use the updateOptions method on the instance returned by tabmate(). For example: instance.updateOptions({ tabWidth: 4 });. This will apply the new tab width for all subsequent interactions.
Q: Does TabMate work with React or other frameworks?
A: TabMate is framework-agnostic and works with any JavaScript application. In React, attach it in useEffect and clean up with the detach method. The library doesn’t interfere with virtual DOM updates since it only listens to keyboard events.
Q: Does it interfere with browser accessibility features?
A: TabMate preserves standard keyboard navigation patterns. Users can still Tab out of the textarea by pressing Escape then Tab, or use Ctrl+Tab where supported. Screen readers and other assistive technologies continue to work normally since the library only modifies indentation behavior.
Changelog:
v0.2.1 (09/30/2025)
- Bugfixes
v0.2.0 (06/30/2025)
- Ignore blank lines when indenting multiple lines







