https://github.com/bejamas/data-slot
vanilla JS behavior primitives for accessible components
https://github.com/bejamas/data-slot
accessibility component-library design-systems headless-ui ui ui-components ui-kit vanilla-js
Last synced: 2 months ago
JSON representation
vanilla JS behavior primitives for accessible components
- Host: GitHub
- URL: https://github.com/bejamas/data-slot
- Owner: bejamas
- License: mit
- Created: 2026-01-07T21:59:16.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-03-30T09:51:03.000Z (2 months ago)
- Last Synced: 2026-03-30T11:35:29.497Z (2 months ago)
- Topics: accessibility, component-library, design-systems, headless-ui, ui, ui-components, ui-kit, vanilla-js
- Language: TypeScript
- Homepage: https://data-slot.com
- Size: 1.9 MB
- Stars: 31
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# data-slot
Headless UI components for vanilla JavaScript. Tiny, accessible, unstyled.
## Features
- **Zero dependencies** - No npm package dependencies, works everywhere
- **Tree-shakeable** - Import only what you use, keep bundles small
- **Accessible** - WAI-ARIA compliant with keyboard navigation built-in
- **Small bundles** - Packages stay compact and tree-shake cleanly
- **Framework-agnostic** - Works with vanilla JavaScript, no framework required
- **TypeScript** - Full TypeScript support with type definitions included
## Quick Start
Add `data-slot` attributes to your HTML and initialize with JavaScript:
```html
Tab One
Tab Two
Content One
Content Two
import { create } from "@data-slot/tabs";
const controllers = create();
controllers[0]?.select("two");
```
The `create()` function auto-discovers all tabs in the DOM and binds them. Use the controller to programmatically control the component.
## Installation
Install individual packages as needed:
```bash
# npm
npm install @data-slot/tabs @data-slot/dialog @data-slot/alert-dialog
# pnpm
pnpm add @data-slot/tabs @data-slot/dialog @data-slot/alert-dialog
# yarn
yarn add @data-slot/tabs @data-slot/dialog @data-slot/alert-dialog
# bun
bun add @data-slot/tabs @data-slot/dialog @data-slot/alert-dialog
```
## Packages
All packages are independently installable. Each package includes its own README with detailed documentation.
| Package | Size | Description | Documentation |
| ---------------------------- | ------ | --------------------------- | -------------------------------------------- |
| `@data-slot/navigation-menu` | 7.2 KB | Dropdown navigation menus | [README](packages/navigation-menu/README.md) |
| `@data-slot/core` | 5.5 KB | Shared utilities | [README](packages/core/README.md) |
| `@data-slot/command` | 4.7 KB | Command palette with search | [README](packages/command/README.md) |
| `@data-slot/hover-card` | 2.6 KB | Hover/focus preview cards | [README](packages/hover-card/README.md) |
| `@data-slot/tabs` | 2.3 KB | Tabbed interfaces, kbd nav | [README](packages/tabs/README.md) |
| `@data-slot/radio-group` | 2.3 KB | Single-select radios, form-ready | [README](packages/radio-group/README.md) |
| `@data-slot/tooltip` | 2.2 KB | Hover/focus tooltips | [README](packages/tooltip/README.md) |
| `@data-slot/popover` | 2.0 KB | Anchored floating content | [README](packages/popover/README.md) |
| `@data-slot/dialog` | 1.9 KB | Modal dialogs, focus trap | [README](packages/dialog/README.md) |
| `@data-slot/alert-dialog` | 1.8 KB | Blocking confirmation dialogs | [README](packages/alert-dialog/README.md) |
| `@data-slot/collapsible` | 1.6 KB | Simple show/hide toggle | [README](packages/collapsible/README.md) |
| `@data-slot/accordion` | 1.4 KB | Collapsible sections | [README](packages/accordion/README.md) |
## API
All components follow the same pattern. You can either auto-discover all instances or create controllers for specific elements.
### Auto-discovery
The `create()` function finds all component instances in the DOM (or within a scope):
```typescript
import { create } from "@data-slot/tabs";
// Find all tabs in the document
const controllers = create(); // Returns TabsController[]
// Or scope to a specific element
const controllers = create(document.querySelector(".my-app"));
```
### Manual creation
Create a controller for a specific element with options:
```typescript
import { createTabs } from "@data-slot/tabs";
const tabs = createTabs(document.querySelector('[data-slot="tabs"]'), {
defaultValue: "news",
onValueChange: (value) => console.log("Selected:", value),
});
tabs.select("sports"); // Programmatic control
tabs.destroy(); // Cleanup when done
```
### Other components
The same pattern applies to all components:
```typescript
import { createDialog } from "@data-slot/dialog";
import { createAlertDialog } from "@data-slot/alert-dialog";
import { createAccordion } from "@data-slot/accordion";
import { createPopover } from "@data-slot/popover";
import { createHoverCard } from "@data-slot/hover-card";
import { createCommand } from "@data-slot/command";
const dialog = createDialog(element);
const alertDialog = createAlertDialog(element);
const accordion = createAccordion(element);
const popover = createPopover(element);
const hoverCard = createHoverCard(element);
const command = createCommand(element);
```
## Styling
Components are unstyled by default. Use `data-state` attributes and ARIA attributes for styling.
### CSS
```css
/* Active tab trigger */
[data-slot="tabs-trigger"][aria-selected="true"] {
font-weight: bold;
border-bottom: 2px solid currentColor;
}
/* Using data-state */
[data-slot="tabs-trigger"][data-state="active"] {
color: blue;
}
[data-slot="tabs-trigger"][data-state="inactive"] {
color: gray;
}
/* Dialog overlay */
[data-slot="dialog"][data-state="open"] [data-slot="dialog-overlay"] {
background: rgba(0, 0, 0, 0.5);
}
/* Accordion content */
[data-slot="accordion-content"][hidden] {
display: none;
}
```
### Tailwind CSS
Use Tailwind's `aria-*` and `data-*` variants:
```html
Tab
Dialog content
```
## Examples
See live examples and component demos at **[data-slot.com](https://data-slot.com)**.
## Browser Support
data-slot uses ES modules and modern JavaScript features. It works in all modern browsers that support:
- ES modules (``)
- `querySelector` and DOM APIs
- Modern JavaScript (ES2017+)
For older browsers, use a bundler like Vite, Rollup, or Webpack with appropriate transpilation.
## Development
This is a monorepo managed with Bun workspaces. Each package is independently buildable and testable.
```bash
# Install dependencies
bun install
# Run tests
bun test
# Type check
bun run typecheck
# Build all packages
bun run build
```
Each package has its own directory in `packages/` with its own `package.json`, source code, and tests.
## License
MIT