Skip to content

Commit 08219ba

Browse files
committed
Accordion component stable release
1 parent ec73050 commit 08219ba

File tree

4 files changed

+91
-113
lines changed

4 files changed

+91
-113
lines changed

demo.html

Lines changed: 7 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -66,64 +66,15 @@ <h2 class="font-lg text-primary my-4">Alert Component Showcase</h2>
6666

6767
<section class="p-4 bg-neutral-50 shadow-md rounded my-6">
6868
<h2 class="font-lg text-primary my-4">Accordion Component Showcase</h2>
69-
70-
<!-- Primary Accordion with Sub-Content -->
71-
<div class="accordion-container" data-variant="primary">
72-
<div class="accordion-item">
73-
<button class="accordion-header" onclick="toggleAccordion(this)" aria-label="Toggle primary accordion item 1">
74-
Primary Accordion - Item 1
75-
</button>
76-
<div class="accordion-content">
77-
<p>This is the main content of the primary accordion item 1.</p>
78-
79-
<!-- Sub-Items within Primary Accordion Item 1 -->
80-
<div class="accordion-sub-item">
81-
<button class="accordion-sub-header" onclick="toggleAccordion(this)" aria-label="Toggle sub-item 1">
82-
Sub-Item 1
83-
</button>
84-
<div class="accordion-sub-content">
85-
<p>This is the content of sub-item 1 under primary accordion item 1.</p>
86-
</div>
87-
</div>
88-
<div class="accordion-sub-item">
89-
<button class="accordion-sub-header" onclick="toggleAccordion(this)" aria-label="Toggle sub-item 2">
90-
Sub-Item 2
91-
</button>
92-
<div class="accordion-sub-content">
93-
<p>This is the content of sub-item 2 under primary accordion item 1.</p>
94-
</div>
95-
</div>
96-
</div>
69+
70+
<div class="kroma-accordion-container" data-variant="secondary">
71+
<div class="kroma-accordion-item" data-header="Primary Accordion - Item 1" data-content="This is the main content of the primary accordion item 1."></div>
72+
<div class="kroma-accordion-item" data-header="Primary Accordion - Item 2" data-content="This is the main content of the primary accordion item 2.">
73+
<div class="kroma-accordion-sub-item" data-header="Sub-Item 1" data-content="This is the content of sub-item 1 under primary accordion item 2."></div>
74+
<div class="kroma-accordion-sub-item" data-header="Sub-Item 2" data-content="This is the content of sub-item 2 under primary accordion item 2."></div>
9775
</div>
76+
</div>
9877

99-
<!-- Primary Accordion Item 2 with Sub-Items -->
100-
<div class="accordion-item">
101-
<button class="accordion-header" onclick="toggleAccordion(this)" aria-label="Toggle primary accordion item 2">
102-
Primary Accordion - Item 2
103-
</button>
104-
<div class="accordion-content">
105-
<p>This is the main content of the primary accordion item 2.</p>
106-
107-
<!-- Sub-Items within Primary Accordion Item 2 -->
108-
<div class="accordion-sub-item">
109-
<button class="accordion-sub-header" onclick="toggleAccordion(this)" aria-label="Toggle sub-item 1">
110-
Sub-Item 1
111-
</button>
112-
<div class="accordion-sub-content">
113-
<p>This is the content of sub-item 1 under primary accordion item 2.</p>
114-
</div>
115-
</div>
116-
<div class="accordion-sub-item">
117-
<button class="accordion-sub-header" onclick="toggleAccordion(this)" aria-label="Toggle sub-item 2">
118-
Sub-Item 2
119-
</button>
120-
<div class="accordion-sub-content">
121-
<p>This is the content of sub-item 2 under primary accordion item 2.</p>
122-
</div>
123-
</div>
124-
</div>
125-
</div>
126-
</div>
12778
</section>
12879

12980
<section class="p-4 bg-neutral-50 shadow-md rounded my-6">

src/css/components/accordion.css

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/* Accordion Container */
2-
.accordion-container {
1+
/* Base Accordion Container */
2+
.kroma-accordion-container {
33
max-width: 100%;
44
margin: auto;
55
padding: var(--space-4);
@@ -9,15 +9,15 @@
99
}
1010

1111
/* Accordion Item */
12-
.accordion-item {
12+
.kroma-accordion-item {
1313
border-bottom: 1px solid var(--neutral-200);
1414
}
15-
.accordion-item:last-child {
15+
.kroma-accordion-item:last-child {
1616
border-bottom: none;
1717
}
1818

1919
/* Accordion Header */
20-
.accordion-header {
20+
.kroma-accordion-header {
2121
display: flex;
2222
justify-content: space-between;
2323
align-items: center;
@@ -32,15 +32,15 @@
3232
border-radius: var(--radius-md);
3333
transition: background-color var(--transition-colors), box-shadow var(--transition-all);
3434
}
35-
.accordion-header:hover,
36-
.accordion-header:focus {
35+
.kroma-accordion-header:hover,
36+
.kroma-accordion-header:focus {
3737
background-color: var(--neutral-100);
3838
outline: none;
3939
}
4040

4141
/* Accordion Content */
42-
.accordion-content,
43-
.accordion-sub-content {
42+
.kroma-accordion-content,
43+
.kroma-accordion-sub-content {
4444
height: 0;
4545
overflow: hidden;
4646
transition: height 0.4s ease;
@@ -49,12 +49,12 @@
4949
}
5050

5151
/* Sub-Item */
52-
.accordion-sub-item {
52+
.kroma-accordion-sub-item {
5353
border-top: 1px solid var(--neutral-200);
5454
padding-left: var(--space-4);
5555
transition: padding 0.3s ease;
5656
}
57-
.accordion-sub-header {
57+
.kroma-accordion-sub-header {
5858
padding: clamp(var(--space-2), 1vw + var(--space-1), var(--space-3));
5959
font-size: 0.9rem;
6060
font-weight: 400;
@@ -67,28 +67,28 @@
6767
border-radius: var(--radius-md);
6868
transition: background-color var(--transition-colors);
6969
}
70-
.accordion-sub-header:hover {
70+
.kroma-accordion-sub-header:hover {
7171
background-color: var(--neutral-100);
7272
}
7373

74-
/* Variants (Dynamic) */
75-
.accordion-container[data-variant] .accordion-header {
74+
/* Variants */
75+
.kroma-accordion-container[data-variant] .kroma-accordion-header {
7676
background-color: var(--variant-bg);
7777
color: var(--variant-text);
7878
box-shadow: var(--variant-shadow);
7979
border: 1px solid var(--variant-border);
8080
}
81-
.accordion-container[data-variant] .accordion-header:hover {
81+
.kroma-accordion-container[data-variant] .kroma-accordion-header:hover {
8282
background-color: var(--variant-hover-bg);
8383
}
8484

8585
/* Responsive Design */
8686
@media (max-width: 768px) {
87-
.accordion-container {
87+
.kroma-accordion-container {
8888
padding: var(--space-2);
8989
}
90-
.accordion-header,
91-
.accordion-sub-header {
90+
.kroma-accordion-header,
91+
.kroma-accordion-sub-header {
9292
padding: var(--space-2);
9393
}
9494
}

src/js/components/accordion.js

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,70 @@
1-
export function toggleAccordion(element) {
1+
document.addEventListener('DOMContentLoaded', () => {
2+
const accordions = document.querySelectorAll('.kroma-accordion-container');
3+
4+
accordions.forEach(container => {
5+
const items = container.querySelectorAll('[data-header]');
6+
7+
items.forEach(item => {
8+
const headerText = item.getAttribute('data-header');
9+
const contentText = item.getAttribute('data-content');
10+
const isSubItem = item.closest('.kroma-accordion-content');
11+
12+
const header = document.createElement('button');
13+
header.classList.add(isSubItem ? 'kroma-accordion-sub-header' : 'kroma-accordion-header');
14+
header.setAttribute('aria-label', `Toggle ${headerText}`);
15+
header.textContent = headerText;
16+
header.onclick = () => toggleAccordion(header);
17+
18+
const content = document.createElement('div');
19+
content.classList.add(isSubItem ? 'kroma-accordion-sub-content' : 'kroma-accordion-content');
20+
content.innerHTML = `<p>${contentText}</p>`;
21+
22+
item.appendChild(header);
23+
item.appendChild(content);
24+
item.removeAttribute('data-header');
25+
item.removeAttribute('data-content');
26+
});
27+
});
28+
});
29+
30+
function toggleAccordion(element) {
231
const content = element.nextElementSibling;
332
const parentItem = content.parentElement;
4-
const isOpen = parentItem.classList.contains('accordion-item-open') || parentItem.classList.contains('accordion-sub-item-open');
5-
33+
const isOpen = parentItem.classList.contains('kroma-accordion-item-open') || parentItem.classList.contains('kroma-accordion-sub-item-open');
34+
635
if (isOpen) {
7-
// Close accordion
8-
content.style.height = content.scrollHeight + 'px'; // Start with current height
9-
content.offsetHeight; // Force reflow
10-
content.style.height = '0'; // Collapse
11-
12-
parentItem.classList.remove('accordion-item-open', 'accordion-sub-item-open');
13-
content.addEventListener('transitionend', function handler() {
14-
content.style.paddingTop = '0';
15-
content.style.paddingBottom = '0';
16-
content.removeEventListener('transitionend', handler);
17-
});
36+
content.style.height = content.scrollHeight + 'px'; // Start with current height
37+
content.offsetHeight; // Force reflow
38+
content.style.height = '0'; // Collapse
39+
40+
parentItem.classList.remove('kroma-accordion-item-open', 'kroma-accordion-sub-item-open');
41+
content.addEventListener('transitionend', function handler() {
42+
content.style.paddingTop = '0';
43+
content.style.paddingBottom = '0';
44+
content.removeEventListener('transitionend', handler);
45+
});
1846
} else {
19-
// Open accordion
20-
const parent = element.closest('.accordion-container, .accordion-item, .accordion-sub-item');
21-
const openSubItems = parent.querySelectorAll('.accordion-item-open > .accordion-content, .accordion-sub-item-open > .accordion-sub-content');
22-
23-
openSubItems.forEach(subItem => {
24-
subItem.style.height = subItem.scrollHeight + 'px';
25-
subItem.offsetHeight; // Force reflow
26-
subItem.style.height = '0';
27-
subItem.parentElement.classList.remove('accordion-item-open', 'accordion-sub-item-open');
28-
});
29-
30-
content.style.height = '0';
31-
content.style.paddingTop = '';
32-
content.style.paddingBottom = '';
33-
parentItem.classList.add('accordion-item-open', 'accordion-sub-item-open');
34-
content.offsetHeight; // Force reflow
35-
content.style.height = content.scrollHeight + 'px'; // Expand to full height
36-
37-
content.addEventListener('transitionend', function handler() {
38-
content.style.height = 'auto';
39-
content.removeEventListener('transitionend', handler);
40-
});
47+
const parent = element.closest('.kroma-accordion-container, .kroma-accordion-item, .kroma-accordion-sub-item');
48+
const openSubItems = parent.querySelectorAll('.kroma-accordion-item-open > .kroma-accordion-content, .kroma-accordion-sub-item-open > .kroma-accordion-sub-content');
49+
50+
openSubItems.forEach(subItem => {
51+
subItem.style.height = subItem.scrollHeight + 'px';
52+
subItem.offsetHeight; // Force reflow
53+
subItem.style.height = '0';
54+
subItem.parentElement.classList.remove('kroma-accordion-item-open', 'kroma-accordion-sub-item-open');
55+
});
56+
57+
content.style.height = '0';
58+
content.style.paddingTop = '';
59+
content.style.paddingBottom = '';
60+
parentItem.classList.add('kroma-accordion-item-open', 'kroma-accordion-sub-item-open');
61+
content.offsetHeight; // Force reflow
62+
content.style.height = content.scrollHeight + 'px'; // Expand to full height
63+
64+
content.addEventListener('transitionend', function handler() {
65+
content.style.height = 'auto';
66+
content.removeEventListener('transitionend', handler);
67+
});
4168
}
42-
}
69+
}
70+

src/js/main.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Import components
22
import { } from './components/alert.js';
3-
import { toggleAccordion } from './components/accordion.js';
3+
import { } from './components/accordion.js';
44
import { showHologram } from './components/hologram.js';
55
import { showTabContent } from './components/tabs.js';
66
import { showToast, dismissToast, startAutoDismiss, pauseAllProgressBars } from './components/toast.js';
@@ -33,7 +33,6 @@ document.addEventListener("DOMContentLoaded", () => {
3333
});
3434

3535
// Export functions globally if needed
36-
window.toggleAccordion = toggleAccordion;
3736
window.showHologram = showHologram;
3837
window.showTabContent = showTabContent;
3938
window.showToast = showToast;

0 commit comments

Comments
 (0)