diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts
index 70f88e5a..fd300ed5 100644
--- a/packages/ui/src/components/index.ts
+++ b/packages/ui/src/components/index.ts
@@ -38,6 +38,7 @@ export * from './skeleton';
export * from './slider';
export * from './switch';
export * from './tabs';
+export * from './tags-input';
export * from './textarea';
export * from './toast';
export * from './toggle';
diff --git a/packages/ui/src/components/tags-input/index.ts b/packages/ui/src/components/tags-input/index.ts
new file mode 100644
index 00000000..78bbed90
--- /dev/null
+++ b/packages/ui/src/components/tags-input/index.ts
@@ -0,0 +1,8 @@
+import STagsInputRoot from './tags-input-root.vue';
+import STagsInputInput from './tags-input-input.vue';
+import STagsInputItem from './tags-input-item.vue';
+import STagsInputItemText from './tags-input-item-text.vue';
+import STagsInputItemDelete from './tags-input-item-delete.vue';
+import STagsInput from './tags-input.vue';
+
+export { STagsInputRoot, STagsInputInput, STagsInputItem, STagsInputItemText, STagsInputItemDelete, STagsInput };
diff --git a/packages/ui/src/components/tags-input/tags-input-input.vue b/packages/ui/src/components/tags-input/tags-input-input.vue
new file mode 100644
index 00000000..29c4b7bd
--- /dev/null
+++ b/packages/ui/src/components/tags-input/tags-input-input.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/tags-input/tags-input-item-delete.vue b/packages/ui/src/components/tags-input/tags-input-item-delete.vue
new file mode 100644
index 00000000..bd3f1ed1
--- /dev/null
+++ b/packages/ui/src/components/tags-input/tags-input-item-delete.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/tags-input/tags-input-item-text.vue b/packages/ui/src/components/tags-input/tags-input-item-text.vue
new file mode 100644
index 00000000..d0a70789
--- /dev/null
+++ b/packages/ui/src/components/tags-input/tags-input-item-text.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/tags-input/tags-input-item.vue b/packages/ui/src/components/tags-input/tags-input-item.vue
new file mode 100644
index 00000000..238a1c32
--- /dev/null
+++ b/packages/ui/src/components/tags-input/tags-input-item.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/tags-input/tags-input-root.vue b/packages/ui/src/components/tags-input/tags-input-root.vue
new file mode 100644
index 00000000..dd368dbe
--- /dev/null
+++ b/packages/ui/src/components/tags-input/tags-input-root.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/tags-input/tags-input.vue b/packages/ui/src/components/tags-input/tags-input.vue
new file mode 100644
index 00000000..bef6bc3a
--- /dev/null
+++ b/packages/ui/src/components/tags-input/tags-input.vue
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/components/tags-input/types.ts b/packages/ui/src/components/tags-input/types.ts
new file mode 100644
index 00000000..53f97fbf
--- /dev/null
+++ b/packages/ui/src/components/tags-input/types.ts
@@ -0,0 +1,43 @@
+import type {
+ AcceptableInputValue,
+ ClassValue,
+ TagsInputRootEmits,
+ TagsInputInputProps as _TagsInputInputProps,
+ TagsInputItemDeleteProps as _TagsInputItemDeleteProps,
+ TagsInputItemProps as _TagsInputItemProps,
+ TagsInputItemTextProps as _TagsInputItemTextProps,
+ TagsInputRootProps as _TagsInputRootProps
+} from '@soybean-ui/primitives';
+import type { TagsInputSlots, ThemeSize } from '@soybean-ui/variants';
+
+export interface TagsInputRootProps extends _TagsInputRootProps {
+ size?: ThemeSize;
+}
+
+export interface TagsInputInputProps extends _TagsInputInputProps {
+ size?: ThemeSize;
+}
+
+export interface TagsInputItemProps extends _TagsInputItemProps {
+ size?: ThemeSize;
+}
+
+export interface TagsInputItemTextProps extends _TagsInputItemTextProps {
+ size?: ThemeSize;
+}
+
+export interface TagsInputItemDeleteProps extends _TagsInputItemDeleteProps {
+ size?: ThemeSize;
+ iconClass?: ClassValue;
+}
+
+export type TagsInputUi = Partial>;
+
+export interface TagsInputProps extends TagsInputRootProps, TagsInputInputProps {
+ disabledValue?: T[];
+ ui?: TagsInputUi;
+}
+
+export type TagsInputEmits = TagsInputRootEmits;
+
+export type { TagsInputRootEmits };
diff --git a/packages/variants/src/index.ts b/packages/variants/src/index.ts
index 680fc268..30952a98 100644
--- a/packages/variants/src/index.ts
+++ b/packages/variants/src/index.ts
@@ -36,6 +36,7 @@ export * from './variants/skeleton';
export * from './variants/slider';
export * from './variants/switch';
export * from './variants/tabs';
+export * from './variants/tags-input';
export * from './variants/textarea';
export * from './variants/toast';
export * from './variants/toggle';
diff --git a/packages/variants/src/variants/tags-input.ts b/packages/variants/src/variants/tags-input.ts
new file mode 100644
index 00000000..af4b6977
--- /dev/null
+++ b/packages/variants/src/variants/tags-input.ts
@@ -0,0 +1,73 @@
+// @unocss-include
+import { tv } from 'tailwind-variants';
+
+export const tagsInputVariants = tv({
+ slots: {
+ root: [
+ `flex flex-wrap gap-2 items-center rounded-md border border-input bg-background`,
+ `focus-within:(ring-2 ring-offset-2 ring-primary) disabled:(cursor-not-allowed opacity-50)`
+ ],
+ input: `focus:outline-none flex-1 bg-transparent`,
+ item: `flex items-center rounded-md bg-accent data-[state=active]:(ring-2 ring-offset-2 ring-accent-foreground/20) ring-offset-background`,
+ itemText: `rounded bg-transparent`,
+ itemDelete: `flex rounded bg-transparent mr-1 text-foreground hover:text-foreground/80`,
+ itemDeleteIcon: `cursor-pointer`
+ },
+ variants: {
+ size: {
+ xs: {
+ root: 'px-1.5 py-0.75 text-xs',
+ input: 'min-h-4 px-1.5 text-xs',
+ item: 'h-4',
+ itemText: 'py-0.75 px-1.5 text-xs',
+ itemDelete: 'mr-1.5',
+ itemDeleteIcon: 'size-3'
+ },
+ sm: {
+ root: 'px-2 py-0.75 text-sm',
+ input: 'min-h-5 px-2 text-sm',
+ item: 'h-5',
+ itemText: 'py-0.75 px-2 text-sm',
+ itemDelete: 'mr-2',
+ itemDeleteIcon: 'size-3.5'
+ },
+ md: {
+ root: 'px-2.5 py-1 text-sm',
+ input: 'min-h-5.5 px-2.5 text-sm',
+ item: 'h-5.5',
+ itemText: 'py-1 px-2.5 text-sm',
+ itemDelete: 'mr-2.5',
+ itemDeleteIcon: 'size-4'
+ },
+ lg: {
+ root: 'px-3 py-1.25 text-base',
+ input: 'min-h-6 px-3 text-base',
+ item: 'h-6',
+ itemText: 'py-1.25 px-3 text-base',
+ itemDelete: 'mr-3',
+ itemDeleteIcon: 'size-4.5'
+ },
+ xl: {
+ root: 'px-3.5 py-1.5 text-base',
+ input: 'min-h-6.5 px-3.5 text-base',
+ item: 'h-6.5',
+ itemText: 'py-1.5 px-3.5 text-base',
+ itemDelete: 'mr-3.5',
+ itemDeleteIcon: 'size-5'
+ },
+ xxl: {
+ root: 'px-4 py-1.75 text-lg',
+ input: 'min-h-8 px-4 text-lg',
+ item: 'h-8',
+ itemText: 'py-1.75 px-4 text-lg',
+ itemDelete: 'mr-4',
+ itemDeleteIcon: 'size-5.5'
+ }
+ }
+ },
+ defaultVariants: {
+ size: 'md'
+ }
+});
+
+export type TagsInputSlots = keyof typeof tagsInputVariants.slots;
diff --git a/src/views/ui/index.vue b/src/views/ui/index.vue
index ba715e39..3fad048d 100644
--- a/src/views/ui/index.vue
+++ b/src/views/ui/index.vue
@@ -45,6 +45,7 @@ import UiSlider from './modules/slider.vue';
import UiSonner from './modules/sonner.vue';
import UiSwitch from './modules/switch.vue';
import UiTabs from './modules/tabs.vue';
+import UiTagsInput from './modules/tags-input.vue';
import UiTextarea from './modules/textarea.vue';
import UiToast from './modules/toast.vue';
import UiToggle from './modules/toggle.vue';
@@ -268,6 +269,11 @@ const tabs: TabConfig[] = [
label: 'Tabs',
component: UiTabs
},
+ {
+ value: 'tags-input',
+ label: 'TagsInput',
+ component: UiTagsInput
+ },
{
value: 'textarea',
label: 'Textarea',
diff --git a/src/views/ui/modules/tags-input.vue b/src/views/ui/modules/tags-input.vue
new file mode 100644
index 00000000..7889e7b6
--- /dev/null
+++ b/src/views/ui/modules/tags-input.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+