@magic-spells/tab-group 0.1.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +78 -183
- package/dist/tab-group.cjs.js +226 -114
- package/dist/tab-group.cjs.js.map +1 -1
- package/dist/tab-group.css +0 -76
- package/dist/tab-group.esm.js +227 -114
- package/dist/tab-group.esm.js.map +1 -1
- package/dist/tab-group.js +226 -114
- package/dist/tab-group.js.map +1 -1
- package/dist/tab-group.min.css +1 -1
- package/dist/tab-group.min.js +1 -1
- package/package.json +12 -13
- package/tab-group.d.ts +46 -0
- package/dist/scss/tab-group.scss +0 -125
- package/dist/scss/variables.scss +0 -0
- package/dist/tab-group.scss +0 -2
- package/src/index.scss +0 -2
- package/src/scss/tab-group.scss +0 -125
- package/src/scss/variables.scss +0 -0
- package/src/tab-group.js +0 -277
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2026 Magic Spells (Cory Schulz)
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,46 +1,35 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Tab Group
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
5
5
|
|
|
6
|
-
A lightweight, accessible tab interface web component with keyboard navigation
|
|
6
|
+
A lightweight, accessible tab interface web component with keyboard navigation. Ships only structural CSS — you bring your own styles.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
[Live Demo](https://magic-spells.github.io/tab-group/demo/) - See it in action!
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Features
|
|
11
11
|
|
|
12
12
|
- **Fully Accessible** - Built following WAI-ARIA Tab pattern guidelines
|
|
13
13
|
- **Custom Events** - Listen for tab changes with detailed event data
|
|
14
14
|
- **Keyboard Navigation** - Complete keyboard support for accessibility
|
|
15
15
|
- **Auto Consistency** - Ensures tab buttons and panels stay in sync
|
|
16
|
-
- **
|
|
16
|
+
- **Zero Opinions** - No cosmetic CSS; style it however you want
|
|
17
17
|
- **Zero Dependencies** - Lightweight and standalone
|
|
18
18
|
- **Easy Integration** - Works with any framework or vanilla JS
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Installation
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
# npm
|
|
24
23
|
npm install @magic-spells/tab-group
|
|
25
|
-
|
|
26
|
-
# yarn
|
|
27
|
-
yarn add @magic-spells/tab-group
|
|
28
|
-
|
|
29
|
-
# pnpm
|
|
30
|
-
pnpm add @magic-spells/tab-group
|
|
31
24
|
```
|
|
32
25
|
|
|
33
|
-
##
|
|
34
|
-
|
|
35
|
-
### Basic Implementation
|
|
26
|
+
## Usage
|
|
36
27
|
|
|
37
28
|
```html
|
|
38
|
-
<!-- Import the component -->
|
|
39
29
|
<script type="module">
|
|
40
30
|
import '@magic-spells/tab-group';
|
|
41
31
|
</script>
|
|
42
32
|
|
|
43
|
-
<!-- Use the component -->
|
|
44
33
|
<tab-group>
|
|
45
34
|
<tab-list>
|
|
46
35
|
<tab-button>First Tab</tab-button>
|
|
@@ -71,190 +60,88 @@ pnpm add @magic-spells/tab-group
|
|
|
71
60
|
document
|
|
72
61
|
.querySelector('tab-group')
|
|
73
62
|
.addEventListener('tabchange', (event) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// Access detailed event data
|
|
77
|
-
const {
|
|
78
|
-
previousIndex, // Index of previous tab
|
|
79
|
-
currentIndex, // Index of current tab
|
|
80
|
-
previousTab, // Previous tab element
|
|
81
|
-
currentTab, // Current tab element
|
|
82
|
-
previousPanel, // Previous panel element
|
|
83
|
-
currentPanel, // Current panel element
|
|
84
|
-
} = event.detail;
|
|
85
|
-
|
|
86
|
-
// Do something with the data
|
|
87
|
-
console.log(
|
|
88
|
-
`Changed from tab ${previousIndex} to tab ${currentIndex}`
|
|
89
|
-
);
|
|
63
|
+
const { previousIndex, currentIndex } = event.detail;
|
|
64
|
+
console.log(`Changed from tab ${previousIndex} to tab ${currentIndex}`);
|
|
90
65
|
});
|
|
91
66
|
```
|
|
92
67
|
|
|
93
|
-
##
|
|
94
|
-
|
|
95
|
-
### CSS Variables
|
|
68
|
+
## Styling
|
|
96
69
|
|
|
97
|
-
The
|
|
70
|
+
The component ships only structural CSS (display modes, overflow, hidden state). All visual styling is yours. Target the custom elements and ARIA attributes directly:
|
|
98
71
|
|
|
99
72
|
```css
|
|
100
|
-
tab-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
--color-text: #333333;
|
|
104
|
-
--color-border: #dddddd;
|
|
105
|
-
--color-border-hover: #bbbbbb;
|
|
106
|
-
--color-primary: #3366ff;
|
|
107
|
-
--color-hover: #f0f5ff;
|
|
108
|
-
--color-focus: #b3cbff;
|
|
109
|
-
|
|
110
|
-
/* Panel styling */
|
|
111
|
-
--panel-background: white;
|
|
112
|
-
--panel-border: 1px solid var(--color-border);
|
|
113
|
-
--panel-padding: 1rem;
|
|
114
|
-
--panel-radius: 0 0 0.5rem 0.5rem;
|
|
115
|
-
--panel-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
116
|
-
|
|
117
|
-
/* Tab list styling */
|
|
118
|
-
--tab-list-gap: 0.25rem;
|
|
119
|
-
--tab-list-padding: 0.5rem 0.5rem 0;
|
|
120
|
-
--tab-list-background: transparent;
|
|
121
|
-
--tab-list-border-bottom: 1px solid var(--color-border);
|
|
122
|
-
--tab-list-radius: 0.5rem 0.5rem 0 0;
|
|
123
|
-
|
|
124
|
-
/* Tab button styling */
|
|
125
|
-
--tab-button-radius: 0.25rem 0.25rem 0 0;
|
|
126
|
-
--tab-active-background: white;
|
|
127
|
-
--tab-active-color: var(--color-primary);
|
|
128
|
-
--tab-active-font-weight: 500;
|
|
129
|
-
--tab-active-shadow: none;
|
|
130
|
-
--tab-active-transform: translateY(0);
|
|
131
|
-
|
|
132
|
-
/* Tab indicator styling */
|
|
133
|
-
--tab-indicator-height: 2px;
|
|
134
|
-
--tab-indicator-color: var(--color-primary);
|
|
135
|
-
--tab-indicator-left: 0;
|
|
136
|
-
--tab-indicator-right: 0;
|
|
73
|
+
tab-list {
|
|
74
|
+
gap: 0.25rem;
|
|
75
|
+
border-bottom: 1px solid #ddd;
|
|
137
76
|
}
|
|
138
|
-
```
|
|
139
77
|
|
|
140
|
-
|
|
78
|
+
tab-button {
|
|
79
|
+
padding: 0.5rem 1rem;
|
|
80
|
+
border-bottom: 2px solid transparent;
|
|
81
|
+
}
|
|
141
82
|
|
|
142
|
-
|
|
83
|
+
tab-button[aria-selected="true"] {
|
|
84
|
+
color: #3366ff;
|
|
85
|
+
border-bottom-color: #3366ff;
|
|
86
|
+
}
|
|
143
87
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
$border-radius: 0.5rem
|
|
149
|
-
);
|
|
88
|
+
tab-panel {
|
|
89
|
+
padding: 1rem;
|
|
90
|
+
}
|
|
91
|
+
```
|
|
150
92
|
|
|
151
|
-
|
|
152
|
-
@use "@magic-spells/tab-group/scss/variables" with (
|
|
153
|
-
$color-primary: #3366ff,
|
|
154
|
-
$border-radius: 0.5rem
|
|
155
|
-
);
|
|
156
|
-
@use "@magic-spells/tab-group/scss/tab-group";
|
|
93
|
+
Or use Tailwind utility classes — no overrides needed.
|
|
157
94
|
|
|
158
|
-
|
|
159
|
-
@use "node_modules/@magic-spells/tab-group/dist/tab-group.scss";
|
|
160
|
-
@use "node_modules/@magic-spells/tab-group/dist/scss/tab-group";
|
|
161
|
-
```
|
|
95
|
+
### What the component CSS includes
|
|
162
96
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
// Colors
|
|
169
|
-
$color-background: #ffffff !default;
|
|
170
|
-
$color-text: #333333 !default;
|
|
171
|
-
$color-border: #dddddd !default;
|
|
172
|
-
$color-border-hover: #bbbbbb !default;
|
|
173
|
-
$color-border-dark: #999999 !default;
|
|
174
|
-
$color-primary: #3366ff !default;
|
|
175
|
-
$color-hover: #f0f5ff !default;
|
|
176
|
-
$color-focus: #b3cbff !default;
|
|
177
|
-
|
|
178
|
-
// Border radius
|
|
179
|
-
$border-radius: 0.5rem !default;
|
|
180
|
-
|
|
181
|
-
// Box shadow
|
|
182
|
-
$box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1) !default;
|
|
183
|
-
|
|
184
|
-
// Tab list
|
|
185
|
-
$tab-list-gap: 0.25rem !default;
|
|
186
|
-
$tab-list-padding: 0.5rem 0.5rem 0 !default;
|
|
187
|
-
$tab-list-background: transparent !default;
|
|
188
|
-
$tab-list-border-bottom: 1px solid $color-border !default;
|
|
189
|
-
$tab-list-radius: $border-radius $border-radius 0 0 !default;
|
|
190
|
-
|
|
191
|
-
// Tab button
|
|
192
|
-
$tab-button-radius: 0.25rem 0.25rem 0 0 !default;
|
|
193
|
-
$tab-active-background: white !default;
|
|
194
|
-
$tab-active-color: $color-primary !default;
|
|
195
|
-
$tab-active-font-weight: 500 !default;
|
|
196
|
-
$tab-active-shadow: none !default;
|
|
197
|
-
$tab-active-transform: translateY(0) !default;
|
|
198
|
-
|
|
199
|
-
// Tab indicator
|
|
200
|
-
$tab-indicator-height: 2px !default;
|
|
201
|
-
$tab-indicator-color: $color-primary !default;
|
|
202
|
-
$tab-indicator-left: 0 !default;
|
|
203
|
-
$tab-indicator-right: 0 !default;
|
|
204
|
-
|
|
205
|
-
// Panel
|
|
206
|
-
$panel-background: white !default;
|
|
207
|
-
$panel-border: 1px solid $color-border !default;
|
|
208
|
-
$panel-padding: 1rem !default;
|
|
209
|
-
$panel-radius: 0 0 $border-radius $border-radius !default;
|
|
210
|
-
$panel-shadow: $box-shadow !default;
|
|
97
|
+
```css
|
|
98
|
+
tab-group { display: block; }
|
|
99
|
+
tab-list { display: flex; overflow-x: auto; overflow-y: hidden; }
|
|
100
|
+
tab-button { display: block; cursor: pointer; user-select: none; }
|
|
101
|
+
tab-panel[hidden] { display: none; }
|
|
211
102
|
```
|
|
212
103
|
|
|
213
|
-
|
|
104
|
+
That's it. No fonts, colors, spacing, borders, transitions, shadows, or media queries.
|
|
214
105
|
|
|
215
|
-
|
|
106
|
+
## Animated Transitions
|
|
216
107
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
--color-primary: #4299e1;
|
|
224
|
-
--color-hover: #1a202c;
|
|
225
|
-
--color-focus: #2c5282;
|
|
226
|
-
--panel-background: #1e293b;
|
|
227
|
-
--panel-border: 1px solid #4a5568;
|
|
228
|
-
--panel-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
|
229
|
-
--tab-active-color: #63b3ed;
|
|
230
|
-
--tab-indicator-color: #63b3ed;
|
|
231
|
-
}
|
|
108
|
+
Add CSS animation classes to smoothly transition between panels. The component orchestrates the lifecycle — you define the animations.
|
|
109
|
+
|
|
110
|
+
```html
|
|
111
|
+
<tab-group animate-out-class="fade-out" animate-in-class="fade-in" animate-timeout="500">
|
|
112
|
+
...
|
|
113
|
+
</tab-group>
|
|
232
114
|
```
|
|
233
115
|
|
|
234
|
-
|
|
116
|
+
| Attribute | Description | Default |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `animate-out-class` | CSS class added to the outgoing panel during exit | none (instant) |
|
|
119
|
+
| `animate-in-class` | CSS class added to the incoming panel during enter | none (instant) |
|
|
120
|
+
| `animate-timeout` | Fallback timeout in ms if `animationend` never fires | `500` |
|
|
235
121
|
|
|
236
122
|
```css
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
--tab-indicator-height: 0;
|
|
123
|
+
@keyframes fade-out {
|
|
124
|
+
from { opacity: 1; }
|
|
125
|
+
to { opacity: 0; }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@keyframes fade-in {
|
|
129
|
+
from { opacity: 0; }
|
|
130
|
+
to { opacity: 1; }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
tab-panel.fade-out {
|
|
134
|
+
animation: fade-out 0.25s ease-out forwards;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
tab-panel.fade-in {
|
|
138
|
+
animation: fade-in 0.25s ease-out forwards;
|
|
254
139
|
}
|
|
255
140
|
```
|
|
256
141
|
|
|
257
|
-
|
|
142
|
+
Either attribute works independently. No attributes = original instant behavior. ARIA updates and the `tabchange` event always fire immediately, before any animation. Rapid clicks cancel cleanly via AbortController.
|
|
143
|
+
|
|
144
|
+
## Accessibility
|
|
258
145
|
|
|
259
146
|
The Tab Group component follows the [WAI-ARIA Tabs Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/) with:
|
|
260
147
|
|
|
@@ -266,7 +153,7 @@ The Tab Group component follows the [WAI-ARIA Tabs Pattern](https://www.w3.org/W
|
|
|
266
153
|
- `Home` to move to the first tab
|
|
267
154
|
- `End` to move to the last tab
|
|
268
155
|
|
|
269
|
-
##
|
|
156
|
+
## API Reference
|
|
270
157
|
|
|
271
158
|
### Components
|
|
272
159
|
|
|
@@ -277,22 +164,30 @@ The Tab Group component follows the [WAI-ARIA Tabs Pattern](https://www.w3.org/W
|
|
|
277
164
|
| `<tab-button>` | Individual tab trigger |
|
|
278
165
|
| `<tab-panel>` | Content container for each tab |
|
|
279
166
|
|
|
167
|
+
### Attributes
|
|
168
|
+
|
|
169
|
+
| Attribute | Element | Description | Default |
|
|
170
|
+
|---|---|---|---|
|
|
171
|
+
| `animate-out-class` | `<tab-group>` | CSS class for exit animation on outgoing panel | none |
|
|
172
|
+
| `animate-in-class` | `<tab-group>` | CSS class for enter animation on incoming panel | none |
|
|
173
|
+
| `animate-timeout` | `<tab-group>` | Fallback timeout (ms) if `animationend` doesn't fire | `500` |
|
|
174
|
+
|
|
280
175
|
### Events
|
|
281
176
|
|
|
282
177
|
| Event | Detail | Description |
|
|
283
178
|
| ----------- | --------------------------------------------------------------------------------------- | --------------------------------- |
|
|
284
179
|
| `tabchange` | `{ previousIndex, currentIndex, previousTab, currentTab, previousPanel, currentPanel }` | Fired when the active tab changes |
|
|
285
180
|
|
|
286
|
-
##
|
|
181
|
+
## Examples
|
|
287
182
|
|
|
288
183
|
Check out more examples in the [demo directory](https://github.com/magic-spells/tab-group/tree/main/demo).
|
|
289
184
|
|
|
290
|
-
##
|
|
185
|
+
## License
|
|
291
186
|
|
|
292
187
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
293
188
|
|
|
294
189
|
---
|
|
295
190
|
|
|
296
191
|
<p align="center">
|
|
297
|
-
Made
|
|
192
|
+
Made by <a href="https://github.com/coryschulz">Cory Schulz</a>
|
|
298
193
|
</p>
|