diff --git a/theme/components/Tag/Tag.ts b/theme/components/Tag/Tag.ts
index 047ce7d698..6ea4c41d10 100644
--- a/theme/components/Tag/Tag.ts
+++ b/theme/components/Tag/Tag.ts
@@ -3,9 +3,11 @@ import {
createMultiStyleConfigHelpers,
defineStyle,
} from '@chakra-ui/styled-system';
+import { mode } from '@chakra-ui/theme-tools';
import getDefaultTransitionProps from '../../utils/getDefaultTransitionProps';
import Badge from '../Badge';
+
const transitionProps = getDefaultTransitionProps();
const { defineMultiStyleConfig, definePartsStyle } =
@@ -15,6 +17,23 @@ const variants = {
subtle: definePartsStyle((props) => ({
container: Badge.variants?.subtle(props),
})),
+ select: definePartsStyle((props) => ({
+ container: {
+ bg: mode('gray.100', 'gray.800')(props),
+ color: mode('gray.500', 'whiteAlpha.800')(props),
+ _hover: {
+ color: 'blue.400',
+ opacity: 0.76,
+ },
+ [`
+ &[data-selected=true],
+ &[data-selected=true][aria-selected=true]
+ `]: {
+ bg: mode('blue.500', 'blue.900')(props),
+ color: 'whiteAlpha.800',
+ },
+ },
+ })),
};
const sizes = {
diff --git a/ui/shared/tagGroupSelect/TagGroupSelect.pw.tsx b/ui/shared/tagGroupSelect/TagGroupSelect.pw.tsx
new file mode 100644
index 0000000000..4ccc12110c
--- /dev/null
+++ b/ui/shared/tagGroupSelect/TagGroupSelect.pw.tsx
@@ -0,0 +1,22 @@
+import _noop from 'lodash/noop';
+import React from 'react';
+
+import { test, expect } from 'playwright/lib';
+
+import TagGroupSelect from './TagGroupSelect';
+
+test.use({ viewport: { width: 480, height: 140 } });
+
+test('base view +@dark-mode', async({ render }) => {
+ const component = await render(
+ ,
+ );
+
+ await component.getByText('Option 2').hover();
+
+ await expect(component).toHaveScreenshot();
+});
diff --git a/ui/shared/tagGroupSelect/TagGroupSelect.tsx b/ui/shared/tagGroupSelect/TagGroupSelect.tsx
new file mode 100644
index 0000000000..4bf53b2ce1
--- /dev/null
+++ b/ui/shared/tagGroupSelect/TagGroupSelect.tsx
@@ -0,0 +1,56 @@
+import { HStack, Tag } from '@chakra-ui/react';
+import React from 'react';
+
+type Props = {
+ items: Array<{ id: T; title: string }>;
+} & (
+ {
+ value: T;
+ onChange: (value: T) => void;
+ isMulti?: false;
+ } | {
+ value: Array;
+ onChange: (value: Array) => void;
+ isMulti: true;
+ }
+)
+
+const TagGroupSelect = ({ items, value, isMulti, onChange }: Props) => {
+ const onItemClick = React.useCallback((event: React.SyntheticEvent) => {
+ const itemValue = (event.currentTarget as HTMLDivElement).getAttribute('data-id') as T;
+ if (isMulti) {
+ let newValue;
+ if (value.includes(itemValue)) {
+ newValue = value.filter(i => i !== itemValue);
+ } else {
+ newValue = [ ...value, itemValue ];
+ }
+ onChange(newValue);
+ } else {
+ onChange(itemValue);
+ }
+ }, [ isMulti, onChange, value ]);
+
+ return (
+
+ { items.map(item => {
+ const isSelected = isMulti ? value.includes(item.id) : value === item.id;
+ return (
+
+ { item.title }
+
+ );
+ }) }
+
+ );
+};
+
+export default TagGroupSelect;
diff --git a/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_dark-color-mode_base-view-dark-mode-1.png b/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_dark-color-mode_base-view-dark-mode-1.png
new file mode 100644
index 0000000000..4684f4fcdc
Binary files /dev/null and b/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_dark-color-mode_base-view-dark-mode-1.png differ
diff --git a/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_default_base-view-dark-mode-1.png b/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_default_base-view-dark-mode-1.png
new file mode 100644
index 0000000000..b6a14300fc
Binary files /dev/null and b/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_default_base-view-dark-mode-1.png differ