diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/AddBadgeListItem/AddBadgeListItem.tsx b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/AddBadgeListItem/AddBadgeListItem.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..1643adf21a6ee59e857be8d22ded12fcae92e3c1
--- /dev/null
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/AddBadgeListItem/AddBadgeListItem.tsx
@@ -0,0 +1,32 @@
+import { Badge } from "@mantine/core";
+
+import CS from "metabase/css/core/index.css";
+import { ActionIcon, Icon } from "metabase/ui";
+
+type AddBadgeListItemProps = {
+  name: string;
+  onClick: () => void;
+};
+
+export const AddBadgeListItem = ({ name, onClick }: AddBadgeListItemProps) => (
+  <Badge
+    classNames={{
+      inner: CS.cursorPointer,
+    }}
+    bg="var(--mb-color-bg-light)"
+    tt="capitalize"
+    size="lg"
+    variant="transparent"
+    c="var(--mb-color-text-brand)"
+    pr="sm"
+    pl="xs"
+    leftSection={
+      <ActionIcon radius="xl" size="sm" className={CS.bgMediumHover}>
+        <Icon name="add" c="var(--mb-color-text-brand)" size={10} />
+      </ActionIcon>
+    }
+    onClick={onClick}
+  >
+    {name}
+  </Badge>
+);
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/AddBadgeListItem/AddBadgeListItem.unit.spec.tsx b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/AddBadgeListItem/AddBadgeListItem.unit.spec.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..04ced6356c605d71ef81001c1b6212f1fd739443
--- /dev/null
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/AddBadgeListItem/AddBadgeListItem.unit.spec.tsx
@@ -0,0 +1,30 @@
+import userEvent from "@testing-library/user-event";
+
+import { render, screen } from "__support__/ui";
+
+import { AddBadgeListItem } from "./AddBadgeListItem";
+
+const setup = () => {
+  const name = "test badge";
+  const handleClick = jest.fn();
+  render(<AddBadgeListItem name={name} onClick={handleClick} />);
+  return { handleClick };
+};
+
+describe("AddBadgeListItem", () => {
+  it("renders badge with correct name", () => {
+    setup();
+    expect(screen.getByText("test badge")).toBeInTheDocument();
+  });
+
+  it("calls onClick when clicked", async () => {
+    const { handleClick } = setup();
+    await userEvent.click(screen.getByText("test badge"));
+    expect(handleClick).toHaveBeenCalledTimes(1);
+  });
+
+  it("renders add icon", () => {
+    setup();
+    expect(screen.getByLabelText("add icon")).toBeInTheDocument();
+  });
+});
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/AddBadgeListItem/index.ts b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/AddBadgeListItem/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5075a720b39d8e1d2e2058fed6b881c63d402214
--- /dev/null
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/AddBadgeListItem/index.ts
@@ -0,0 +1 @@
+export * from "./AddBadgeListItem";
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeList.stories.tsx b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeList.stories.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..effba8ec54246e2c64cc6cdcb15e17977d2cfcfb
--- /dev/null
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeList.stories.tsx
@@ -0,0 +1,69 @@
+import { useState } from "react";
+
+import { Box, Stack } from "metabase/ui";
+
+import { BadgeList } from "./BadgeList";
+
+export default {
+  title: "BadgeList",
+  component: BadgeList,
+  parameters: {
+    layout: "fullscreen",
+  },
+};
+
+export const DefaultLayoutBadgeList = {
+  render() {
+    const [items, setItems] = useState(
+      Array.from(Array(5).keys()).map(i => ({
+        name: `item ${i}`,
+        item: i,
+      })),
+    );
+
+    const [selectedItem, setSelectedItem] = useState<{
+      item?: number;
+      index?: number;
+    }>({});
+
+    const onSelectItem = (item?: number, index?: number) => {
+      if (item === selectedItem?.item) {
+        setSelectedItem({});
+      } else {
+        setSelectedItem({ item, index });
+      }
+    };
+
+    const onAddItem = () =>
+      setItems(nextItems => [
+        ...nextItems,
+        { name: `item ${nextItems.length}`, item: nextItems.length },
+      ]);
+
+    const onRemoveItem = (_item?: number, index?: number) => {
+      if (typeof index === "number") {
+        setItems(nextItems => [
+          ...nextItems.slice(0, index),
+          ...nextItems.slice(index + 1),
+        ]);
+      }
+    };
+
+    return (
+      <Stack>
+        <BadgeList
+          items={items}
+          onSelectItem={onSelectItem}
+          onAddItem={onAddItem}
+          onRemoveItem={onRemoveItem}
+          addButtonLabel="Add another item"
+        />
+        <Box p="md">
+          {selectedItem?.item
+            ? `The selected element is ${selectedItem.item} at index ${selectedItem.index}`
+            : "No element has been selected"}
+        </Box>
+      </Stack>
+    );
+  },
+};
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeList.tsx b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeList.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..425abeb9b3b44cffbff364fe9eb5712a9b5bb53c
--- /dev/null
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeList.tsx
@@ -0,0 +1,39 @@
+import { Group, Paper } from "metabase/ui";
+
+import { AddBadgeListItem } from "./AddBadgeListItem";
+import { BadgeListItem } from "./BadgeListItem";
+
+export type BadgeListProps<T> = {
+  items: {
+    name: string;
+    item: T;
+  }[];
+  onSelectItem?: (item?: T, index?: number) => void;
+  onAddItem?: (item?: T) => void;
+  onRemoveItem?: (item?: T, index?: number) => void;
+  addButtonLabel?: string;
+};
+
+export const BadgeList = <T,>({
+  items,
+  onSelectItem,
+  onAddItem,
+  onRemoveItem,
+  addButtonLabel,
+}: BadgeListProps<T>) => (
+  <Paper p="md" w="30rem">
+    <Group spacing="sm">
+      {items.map(({ name, item }, index) => (
+        <BadgeListItem
+          key={`${name}/${index}`}
+          onSelectItem={() => onSelectItem?.(item, index)}
+          onRemoveItem={() => onRemoveItem?.(item, index)}
+          name={name}
+        />
+      ))}
+      {addButtonLabel && (
+        <AddBadgeListItem name={addButtonLabel} onClick={() => onAddItem?.()} />
+      )}
+    </Group>
+  </Paper>
+);
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeList.unit.spec.tsx b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeList.unit.spec.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..dbc2cfbaf64acf0ee9e2d52d0b952564131d9d99
--- /dev/null
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeList.unit.spec.tsx
@@ -0,0 +1,72 @@
+import userEvent from "@testing-library/user-event";
+
+import { render, screen } from "__support__/ui";
+
+import { BadgeList, type BadgeListProps } from "./BadgeList";
+
+type SetupOpts = Partial<BadgeListProps<{ id: number }>>;
+
+const setup = (opts: SetupOpts = {}) => {
+  const items = [
+    { name: "item1", item: { id: 1 } },
+    { name: "item2", item: { id: 2 } },
+  ];
+  const onSelectItem = jest.fn();
+  const onAddItem = jest.fn();
+  const onRemoveItem = jest.fn();
+  const addButtonLabel =
+    "addButtonLabel" in opts ? opts.addButtonLabel : "Add new";
+
+  render(
+    <BadgeList
+      items={items}
+      onSelectItem={onSelectItem}
+      onRemoveItem={onRemoveItem}
+      onAddItem={onAddItem}
+      addButtonLabel={addButtonLabel}
+    />,
+  );
+
+  return {
+    onSelectItem,
+    onAddItem,
+    onRemoveItem,
+  };
+};
+
+describe("BadgeList", () => {
+  it("renders all items", () => {
+    setup();
+    expect(screen.getByText("item1")).toBeInTheDocument();
+    expect(screen.getByText("item2")).toBeInTheDocument();
+  });
+
+  it("renders add button when label is provided", () => {
+    setup();
+    expect(screen.getByText("Add new")).toBeInTheDocument();
+  });
+
+  it("doesn't render add button when label is not provided", () => {
+    setup({ addButtonLabel: undefined });
+    expect(screen.queryByText("Add new")).not.toBeInTheDocument();
+  });
+
+  it("calls onSelectItem with correct item when badge is clicked", async () => {
+    const { onSelectItem } = setup();
+    await userEvent.click(screen.getByText("item1"));
+    expect(onSelectItem).toHaveBeenCalledWith({ id: 1 }, 0);
+  });
+
+  it("calls onRemoveItem with correct item when remove button is clicked", async () => {
+    const { onRemoveItem } = setup();
+    const removeButtons = screen.getAllByLabelText("close icon");
+    await userEvent.click(removeButtons[0]);
+    expect(onRemoveItem).toHaveBeenCalledWith({ id: 1 }, 0);
+  });
+
+  it("calls onAddItem when add button is clicked", async () => {
+    const { onAddItem } = setup();
+    await userEvent.click(screen.getByText("Add new"));
+    expect(onAddItem).toHaveBeenCalled();
+  });
+});
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeListItem/BadgeListItem.tsx b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeListItem/BadgeListItem.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..b34efd656946e8a1daa70ea6ecdbbd6267c990a2
--- /dev/null
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeListItem/BadgeListItem.tsx
@@ -0,0 +1,47 @@
+import { Badge } from "@mantine/core";
+
+import CS from "metabase/css/core/index.css";
+import { ActionIcon, Icon } from "metabase/ui";
+
+type BadgeListItemProps = {
+  onSelectItem?: () => void;
+  onRemoveItem?: () => void;
+  name: string;
+};
+
+export const BadgeListItem = ({
+  name,
+  onRemoveItem,
+  onSelectItem,
+}: BadgeListItemProps) => (
+  <Badge
+    size="lg"
+    tt="capitalize"
+    variant="light"
+    bg="var(--mb-color-brand-light)"
+    c="var(--mb-color-text-brand)"
+    classNames={{
+      root: CS.bgLightHover,
+      inner: CS.cursorPointer,
+    }}
+    onClick={onSelectItem}
+    pr={0}
+    pl="sm"
+    rightSection={
+      <ActionIcon
+        radius="xl"
+        size="sm"
+        ml={0}
+        onClick={e => {
+          e.stopPropagation();
+          onRemoveItem?.();
+        }}
+        className={CS.bgMediumHover}
+      >
+        <Icon name="close" c="var(--mb-color-text-brand)" size={10} />
+      </ActionIcon>
+    }
+  >
+    {name}
+  </Badge>
+);
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeListItem/BadgeListItem.unit.spec.tsx b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeListItem/BadgeListItem.unit.spec.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..bb24ef937cb5195b38fb3ad88923b1b4a60539fd
--- /dev/null
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeListItem/BadgeListItem.unit.spec.tsx
@@ -0,0 +1,44 @@
+import userEvent from "@testing-library/user-event";
+
+import { render, screen } from "__support__/ui";
+
+import { BadgeListItem } from "./BadgeListItem";
+
+const setup = () => {
+  const name = "test badge";
+  const onSelectItem = jest.fn();
+  const onRemoveItem = jest.fn();
+  render(
+    <BadgeListItem
+      name={name}
+      onSelectItem={onSelectItem}
+      onRemoveItem={onRemoveItem}
+    />,
+  );
+  return { onSelectItem, onRemoveItem };
+};
+
+describe("BadgeListItem", () => {
+  it("renders badge with correct name", () => {
+    setup();
+    expect(screen.getByText("test badge")).toBeInTheDocument();
+  });
+
+  it("calls onSelectItem when badge is clicked", async () => {
+    const { onSelectItem } = setup();
+    await userEvent.click(screen.getByText("test badge"));
+    expect(onSelectItem).toHaveBeenCalledTimes(1);
+  });
+
+  it("prevents badge click event when clicking remove button", async () => {
+    const { onSelectItem, onRemoveItem } = setup();
+    await userEvent.click(screen.getByLabelText("close icon"));
+    expect(onRemoveItem).toHaveBeenCalledTimes(1);
+    expect(onSelectItem).not.toHaveBeenCalled();
+  });
+
+  it("renders close icon", () => {
+    setup();
+    expect(screen.getByLabelText("close icon")).toBeInTheDocument();
+  });
+});
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeListItem/index.ts b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeListItem/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..58b16911d43bcffaa298f0d176b83945b13e34fd
--- /dev/null
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/BadgeListItem/index.ts
@@ -0,0 +1 @@
+export * from "./BadgeListItem";
diff --git a/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/index.ts b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..95f8e34c01d6d78aa067f5ee146261a7f6f03aeb
--- /dev/null
+++ b/enterprise/frontend/src/embedding-sdk/components/private/InteractiveQuestion/components/util/BadgeList/index.ts
@@ -0,0 +1 @@
+export * from "./BadgeList";
diff --git a/frontend/src/metabase/css/core/colors.module.css b/frontend/src/metabase/css/core/colors.module.css
index 9b7b68724176ff6add10061d43e36fbc92090479..a8f6db09eda6f06a2331cea6e8f97acf27794b0e 100644
--- a/frontend/src/metabase/css/core/colors.module.css
+++ b/frontend/src/metabase/css/core/colors.module.css
@@ -354,7 +354,8 @@
   background-color: var(--mb-color-bg-light);
 }
 
-.bgMedium {
+.bgMedium,
+.bgMediumHover:hover {
   background-color: var(--mb-color-bg-medium);
 }