diff --git a/src/Select/Select copy.vue b/src/Select/Select copy.vue
deleted file mode 100644
index 51351dbf..00000000
--- a/src/Select/Select copy.vue
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
- (focused = v)">
-
-
-
-
-
-
-
-
-
- {{ item.label }}
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Select/Select.vue b/src/Select/Select.vue
index a1a3c0d5..51351dbf 100644
--- a/src/Select/Select.vue
+++ b/src/Select/Select.vue
@@ -1,15 +1,16 @@
-
-
-
-
-
-
- {{ label }}
-
-
-
- {{ placeholder }}
-
-
-
-
-
-
-
-
-
-
-
- {{ item.label }}
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/src/Select/SelectHeadless.vue b/src/Select/SelectHeadless.vue
new file mode 100644
index 00000000..a1a3c0d5
--- /dev/null
+++ b/src/Select/SelectHeadless.vue
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+ {{ label }}
+
+
+
+ {{ placeholder }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/_pure/Listbox/Boxlist.ts b/src/_pure/Listbox/Boxlist.ts
new file mode 100644
index 00000000..3553d7d0
--- /dev/null
+++ b/src/_pure/Listbox/Boxlist.ts
@@ -0,0 +1,20 @@
+import { defineComponent } from 'vue'
+
+const Listbox = defineComponent({
+ name: 'TListbox',
+ props: {
+ list: {
+ type: Array,
+ required: true,
+ },
+ render: {
+ type: Function,
+ required: true,
+ },
+ },
+ setup(props) {
+ return () => {
+ return props.list.map(item => props.render(item))
+ }
+ },
+})
diff --git a/src/_pure/Listbox/index.tsx b/src/_pure/Listbox/index.tsx
new file mode 100644
index 00000000..289e6b4f
--- /dev/null
+++ b/src/_pure/Listbox/index.tsx
@@ -0,0 +1,25 @@
+import { defineComponent, type SlotsType } from 'vue'
+
+const Listbox = defineComponent(
+ (props: { type: string }) => {
+ return () =>
+ },
+ {
+ name: 'TListbox',
+ props: ['type'],
+ emits: ['change'],
+ }
+)
+
+const ListboxOption = defineComponent({
+ name: 'TListboxOption',
+ props: {
+ value: { type: null },
+ },
+ slots: Object as SlotsType<{
+ default: { foo: string; bar: number } // i want : default: { foo: T; bar: number };
+ }>,
+ setup(props) {
+ return () => <>>
+ },
+})
diff --git a/src/_pure/Popper/Trigger.tsx b/src/_pure/Popper/Trigger.tsx
new file mode 100644
index 00000000..e69de29b
diff --git a/src/_pure/Popper/usePopper.ts b/src/_pure/Popper/usePopper.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/src/_pure/PrimitiveSlot.ts b/src/_pure/PrimitiveSlot.ts
new file mode 100644
index 00000000..3ee190eb
--- /dev/null
+++ b/src/_pure/PrimitiveSlot.ts
@@ -0,0 +1,49 @@
+import { cloneVNode, Comment, defineComponent, Fragment, mergeProps, type VNode } from 'vue'
+
+function renderSlotFragments(children?: VNode[]): VNode[] {
+ if (!children) return []
+ return children.flatMap(child => {
+ if (child.type === Fragment) return renderSlotFragments(child.children as VNode[])
+
+ return [child]
+ })
+}
+
+export const Slot = defineComponent({
+ name: 'PrimitiveSlot',
+ inheritAttrs: false,
+ setup(_, { attrs, slots }) {
+ return () => {
+ if (!slots.default) return null
+
+ const children = renderSlotFragments(slots.default())
+ const firstNonCommentChildrenIndex = children.findIndex(child => child.type !== Comment)
+ if (firstNonCommentChildrenIndex === -1) return children
+
+ const firstNonCommentChildren = children[firstNonCommentChildrenIndex]!
+
+ // remove props ref from being inferred
+ delete firstNonCommentChildren.props?.ref
+
+ const mergedProps = firstNonCommentChildren.props ? mergeProps(attrs, firstNonCommentChildren.props) : attrs
+ // remove class to prevent duplicated
+ if (attrs.class && firstNonCommentChildren.props?.class) delete firstNonCommentChildren.props.class
+ const cloned = cloneVNode(firstNonCommentChildren, mergedProps)
+
+ // Explicitly override props starting with `on`.
+ // It seems cloneVNode from Vue doesn't like overriding `onXXX` props.
+ // So we have to do it manually.
+ for (const prop in mergedProps) {
+ if (prop.startsWith('on')) {
+ cloned.props ||= {}
+ cloned.props[prop] = mergedProps[prop]
+ }
+ }
+
+ if (children.length === 1) return cloned
+
+ children[firstNonCommentChildrenIndex] = cloned
+ return children
+ }
+ },
+})
diff --git a/tsconfig.json b/tsconfig.json
index 366b4ca1..5e9abd8c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -2,6 +2,7 @@
"extends": "@jaskang/tsconfig/vue",
"compilerOptions": {
"baseUrl": ".",
+ "jsxImportSource": "vue",
"types": ["vite/client"],
"paths": {
"@/*": ["./src/*"]