diff --git a/src/components/DxhCollapse.vue b/src/components/DxhCollapse.vue
new file mode 100644
index 0000000..31f73ca
--- /dev/null
+++ b/src/components/DxhCollapse.vue
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ item.header }}
+
+
+ {{ item.content }}
+
+
+
+
+
+
diff --git a/src/components/__tests__/DxhCollapse.spec.ts b/src/components/__tests__/DxhCollapse.spec.ts
new file mode 100644
index 0000000..bcfec76
--- /dev/null
+++ b/src/components/__tests__/DxhCollapse.spec.ts
@@ -0,0 +1,77 @@
+import { describe, it, expect, beforeEach, afterEach } from 'vitest'
+import { mount } from '@vue/test-utils'
+import DxhCollapse from '@/components/DxhCollapse.vue'
+
+describe('DxhCollapse.vue', () => {
+ let wrapper: any
+
+ beforeEach(() => {
+ wrapper = mount(DxhCollapse, {
+ props: {
+ items: [
+ { id: 1, header: 'Header 1', content: 'Content 1' },
+ { id: 2, header: 'Header 2', content: 'Content 2' }
+ ],
+ defaultActiveKey: 1,
+ collapsible: 'header',
+ expandIconPosition: 'left'
+ }
+ })
+ })
+
+ afterEach(() => {
+ wrapper.unmount()
+ })
+
+ it('renders with correct initial state', () => {
+ const header1 = wrapper.find('[data-test="collapse-item-header-1"]')
+ const header2 = wrapper.find('[data-test="collapse-item-header-2"]')
+ const content1 = wrapper.find('[data-test="collapse-item-content-1"]')
+ const content2 = wrapper.find('[data-test="collapse-item-content-2"]')
+
+ expect(header1.classes()).toContain('bg-gray-200')
+ expect(content1.exists()).toBe(true)
+
+ expect(content2.exists()).toBe(false)
+ })
+
+ it('toggles active item on header click', async () => {
+ const header2 = wrapper.find('[data-test="collapse-item-header-2"]')
+ const content2 = wrapper.find('[data-test="collapse-item-content-2"]')
+
+ await header2.trigger('click')
+
+ expect(header2.classes()).toContain('bg-gray-200')
+ expect(content2.exists()).toBe(false)
+
+ const header1 = wrapper.find('[data-test="collapse-item-header-1"]')
+ const content1 = wrapper.find('[data-test="collapse-item-content-1"]')
+ expect(header1.classes()).toContain('bg-gray-200')
+ expect(content1.exists()).toBe(true)
+ })
+
+ it('emits change event on item click', async () => {
+ const header2 = wrapper.find('[data-test="collapse-item-header-2"]')
+
+ await header2.trigger('click')
+
+ expect(wrapper.emitted().change).toBeTruthy()
+ expect(wrapper.emitted().change[0][0]).toEqual([1, 2])
+ })
+
+ it('handles click on expand icon', async () => {
+ const expandIcon2 = wrapper.find('[data-test="collapse-item-expand-icon-2"]')
+ const content2 = wrapper.find('[data-test="collapse-item-content-2"]')
+
+ await expandIcon2.trigger('click')
+
+ const header2 = wrapper.find('[data-test="collapse-item-header-2"]')
+ expect(header2.classes()).toContain('bg-gray-200')
+ expect(content2.exists()).toBe(false)
+
+ const header1 = wrapper.find('[data-test="collapse-item-header-1"]')
+ const content1 = wrapper.find('[data-test="collapse-item-content-1"]')
+ expect(header1.classes()).toContain('bg-gray-200')
+ expect(content1.exists()).toBe(true)
+ })
+})
diff --git a/src/index.ts b/src/index.ts
index ee2ff8d..0babaa6 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,5 @@
import DButton from "./components/DButton.vue"
import DInput from "./components/DInput.vue"
+import DxhCollapse from './components/DxhCollapse.vue'
-export default {DButton, DInput}
\ No newline at end of file
+export default { DButton, DInput, DxhCollapse }
\ No newline at end of file