All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 3s
12 KiB
12 KiB
Accordion
Collapsible accordion component for organizing content into expandable sections.
Tag
Accordion
Props
| Prop | Type | Default | Description |
|---|---|---|---|
title |
string | VNode | Signal |
Required | Accordion section title |
open |
boolean | Signal<boolean> |
false |
Whether the accordion is expanded |
name |
string |
auto-generated |
Group name for radio-style accordions |
class |
string |
'' |
Additional CSS classes |
children |
VNode | Array<VNode> |
Required | Content to display when expanded |
items |
Array |
- |
Array of accordion items (alternative API) |
Live Examples
Basic Accordion
Live Demo
const { Accordion, Div, mount } = window;
const BasicDemo = () => {
const open1 = $(false);
const open2 = $(false);
const open3 = $(false);
return Div({ class: 'flex flex-col gap-2' }, [
Accordion({
title: 'Section 1',
open: open1,
children: Div({ class: 'p-2' }, 'Content for section 1. This is a basic accordion section.')
}),
Accordion({
title: 'Section 2',
open: open2,
children: Div({ class: 'p-2' }, 'Content for section 2. You can put any content here.')
}),
Accordion({
title: 'Section 3',
open: open3,
children: Div({ class: 'p-2' }, 'Content for section 3. Accordions are great for FAQs.')
})
]);
};
mount(BasicDemo, '#demo-basic');
Group Accordion (Radio Style)
Live Demo
const { Accordion, Div, mount } = window;
const GroupDemo = () => {
const openSection = $('section1');
return Div({ class: 'flex flex-col gap-2' }, [
Accordion({
name: 'group',
title: 'Section 1',
open: () => openSection() === 'section1',
children: Div({ class: 'p-2' }, 'Content for section 1. Only one section can be open at a time.')
}),
Accordion({
name: 'group',
title: 'Section 2',
open: () => openSection() === 'section2',
children: Div({ class: 'p-2' }, 'Content for section 2. Opening this will close section 1.')
}),
Accordion({
name: 'group',
title: 'Section 3',
open: () => openSection() === 'section3',
children: Div({ class: 'p-2' }, 'Content for section 3. This is useful for FAQ sections.')
})
]);
};
mount(GroupDemo, '#demo-group');
Using Items Array
Live Demo
const { Accordion, Div, mount } = window;
const ItemsDemo = () => {
const openItems = $({
item1: true,
item2: false,
item3: false
});
return Accordion({
items: [
{
title: 'First Item',
open: () => openItems().item1,
children: Div({ class: 'p-2' }, 'This is the content of the first item.')
},
{
title: 'Second Item',
open: () => openItems().item2,
children: Div({ class: 'p-2' }, 'This is the content of the second item.')
},
{
title: 'Third Item',
open: () => openItems().item3,
children: Div({ class: 'p-2' }, 'This is the content of the third item.')
}
]
});
};
mount(ItemsDemo, '#demo-items');
FAQ Accordion
Live Demo
const { Accordion, Div, mount } = window;
const FaqDemo = () => {
const openFaq = $('faq1');
const faqs = [
{ id: 'faq1', question: 'What is this component?', answer: 'This is an accordion component built with DaisyUI and Tailwind CSS for creating collapsible content sections.' },
{ id: 'faq2', question: 'How do I use it?', answer: 'Simply import the Accordion component and pass title and children props.' },
{ id: 'faq3', question: 'Can I have multiple open?', answer: 'Yes! By default, accordions can be opened independently.' }
];
return Div({ class: 'flex flex-col gap-2' }, faqs.map(faq =>
Accordion({
name: 'faq-group',
title: faq.question,
open: () => openFaq() === faq.id,
children: Div({ class: 'p-2 text-sm' }, faq.answer)
})
));
};
mount(FaqDemo, '#demo-faq');
With Rich Content
Live Demo
const { Accordion, Div, Span, mount } = window;
const RichDemo = () => {
const open1 = $(true);
const open2 = $(false);
return Div({ class: 'flex flex-col gap-2' }, [
Accordion({
title: Span({ class: 'flex items-center gap-2' }, ['📊', 'Statistics']),
open: open1,
children: Div({ class: 'p-2' }, [
Div({ class: 'grid grid-cols-2 gap-4' }, [
Div({ class: 'stat bg-base-100 rounded-lg p-3' }, [
Div({ class: 'stat-title' }, 'Users'),
Div({ class: 'stat-value text-lg' }, '1,234')
]),
Div({ class: 'stat bg-base-100 rounded-lg p-3' }, [
Div({ class: 'stat-title' }, 'Revenue'),
Div({ class: 'stat-value text-lg' }, '$45,678')
])
])
])
}),
Accordion({
title: Span({ class: 'flex items-center gap-2' }, ['👥', 'Team Members']),
open: open2,
children: Div({ class: 'p-2 space-y-2' }, [
Div({ class: 'flex items-center gap-3 p-2 hover:bg-base-100 rounded-lg' }, [
Div({ class: 'avatar placeholder' }, [
Div({ class: 'bg-primary text-primary-content rounded-full w-10 h-10 flex items-center justify-center' }, 'JD')
]),
Div({ class: 'flex-1' }, [
Div({ class: 'font-medium' }, 'John Doe'),
Div({ class: 'text-sm opacity-70' }, 'Developer')
])
])
])
})
]);
};
mount(RichDemo, '#demo-rich');
Form Accordion
Live Demo
const { Accordion, Div, Span, Button, Input, Radio, mount } = window;
const FormAccordion = () => {
const openStep = $('step1');
const formData = $({
name: '',
email: '',
address: '',
payment: 'credit'
});
const updateField = (field, value) => {
formData({ ...formData(), [field]: value });
};
const nextStep = () => {
if (openStep() === 'step1') openStep('step2');
else if (openStep() === 'step2') openStep('step3');
};
const prevStep = () => {
if (openStep() === 'step2') openStep('step1');
else if (openStep() === 'step3') openStep('step2');
};
const handleSubmit = () => {
window.Toast('Form submitted!', 'alert-success', 2000);
};
return Div({ class: 'flex flex-col gap-2' }, [
Accordion({
name: 'form-steps',
title: Span({ class: 'flex items-center gap-2' }, ['1️⃣', 'Personal Information']),
open: () => openStep() === 'step1',
children: Div({ class: 'p-4 space-y-4' }, [
Input({
label: 'Full Name',
value: () => formData().name,
placeholder: 'Enter your name',
oninput: (e) => updateField('name', e.target.value)
}),
Input({
label: 'Email',
type: 'email',
value: () => formData().email,
placeholder: 'email@example.com',
oninput: (e) => updateField('email', e.target.value)
}),
Div({ class: 'flex justify-end mt-2' }, [
Button({
class: 'btn btn-primary btn-sm',
onclick: nextStep,
disabled: () => !formData().name || !formData().email
}, 'Next →')
])
])
}),
Accordion({
name: 'form-steps',
title: Span({ class: 'flex items-center gap-2' }, ['2️⃣', 'Address']),
open: () => openStep() === 'step2',
children: Div({ class: 'p-4 space-y-4' }, [
Input({
label: 'Address',
value: () => formData().address,
placeholder: 'Street address',
oninput: (e) => updateField('address', e.target.value)
}),
Div({ class: 'flex justify-between mt-2' }, [
Button({ class: 'btn btn-ghost btn-sm', onclick: prevStep }, '← Back'),
Button({ class: 'btn btn-primary btn-sm', onclick: nextStep }, 'Next →')
])
])
}),
Accordion({
name: 'form-steps',
title: Span({ class: 'flex items-center gap-2' }, ['3️⃣', 'Payment']),
open: () => openStep() === 'step3',
children: Div({ class: 'p-4 space-y-4' }, [
Div({ class: 'flex flex-col gap-2' }, [
Radio({
label: 'Credit Card',
value: () => formData().payment,
radioValue: 'credit',
onclick: () => updateField('payment', 'credit')
}),
Radio({
label: 'PayPal',
value: () => formData().payment,
radioValue: 'paypal',
onclick: () => updateField('payment', 'paypal')
}),
Radio({
label: 'Bank Transfer',
value: () => formData().payment,
radioValue: 'bank',
onclick: () => updateField('payment', 'bank')
})
]),
Div({ class: 'flex justify-between mt-2' }, [
Button({ class: 'btn btn-ghost btn-sm', onclick: prevStep }, '← Back'),
Button({ class: 'btn btn-success btn-sm', onclick: handleSubmit }, 'Submit')
])
])
})
]);
};
mount(FormAccordion, '#demo-form');
All Variants
Live Demo
const { Accordion, Div, Span, mount } = window;
const VariantsDemo = () => {
const open1 = $(true);
const open2 = $(false);
const open3 = $(false);
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'text-sm font-bold' }, 'Default Accordion'),
Accordion({
title: 'Default style',
open: open1,
children: Div({ class: 'p-2' }, 'Default accordion with standard styling.')
}),
Div({ class: 'text-sm font-bold mt-2' }, 'Custom Styling'),
Accordion({
title: Span({ class: 'text-primary font-bold' }, 'Primary Title'),
open: open2,
class: 'bg-primary/5 border-primary/20',
children: Div({ class: 'p-2' }, 'Accordion with custom styling and primary color.')
}),
Div({ class: 'text-sm font-bold mt-2' }, 'With Icons'),
Accordion({
title: Span({ class: 'flex items-center gap-2' }, ['✨', 'Featured Content']),
open: open3,
children: Div({ class: 'p-2' }, 'Accordion with emoji icons in the title.')
})
]);
};
mount(VariantsDemo, '#demo-variants');