diff --git a/app/packages/components/src/components/PillBadge/PillBadge.tsx b/app/packages/components/src/components/PillBadge/PillBadge.tsx
new file mode 100644
index 0000000000..362bc80b7a
--- /dev/null
+++ b/app/packages/components/src/components/PillBadge/PillBadge.tsx
@@ -0,0 +1,149 @@
+import React, { useState } from "react";
+import CircleIcon from "@mui/icons-material/Circle";
+import { Chip, FormControl, MenuItem, Select } from "@mui/material";
+
+const PillBadge = ({
+ text,
+ color = "default",
+ variant = "filled",
+ showIcon = true,
+}: {
+ text: string | string[] | [string, string][];
+ color?: string;
+ variant?: "filled" | "outlined";
+ showIcon?: boolean;
+}) => {
+ const getInitialChipSelection = (
+ text: string | string[] | [string, string][]
+ ) => {
+ if (typeof text === "string") return text;
+ if (Array.isArray(text)) {
+ if (Array.isArray(text[0])) return text[0][0];
+ return text[0];
+ }
+ return "";
+ };
+
+ const getInitialChipColor = (
+ text: string | string[] | [string, string][],
+ color?: string
+ ) => {
+ if (typeof text === "string") return color;
+ if (Array.isArray(text)) {
+ if (Array.isArray(text[0])) return text[0][1];
+ return color || "default";
+ }
+ return "default";
+ };
+
+ const [chipSelection, setChipSelection] = useState(
+ getInitialChipSelection(text)
+ );
+ const [chipColor, setChipColor] = useState(getInitialChipColor(text, color));
+
+ const COLORS: { [key: string]: string } = {
+ default: "#999999",
+ primary: "#FFB682",
+ error: "error",
+ warning: "warning",
+ info: "info",
+ success: "#8BC18D",
+ };
+
+ const chipStyle: { [key: string]: string | number } = {
+ color: COLORS[chipColor || "default"] || COLORS.default,
+ fontWeight: 500,
+ paddingLeft: 1,
+ };
+
+ return (
+
+ {typeof text === "string" ? (
+
+ ) : undefined
+ }
+ label={text}
+ sx={{
+ ...chipStyle,
+ "& .MuiChip-icon": {
+ marginRight: "-7px",
+ },
+ "& .MuiChip-label": {
+ marginBottom: "1px",
+ },
+ }}
+ variant={variant as "filled" | "outlined" | undefined}
+ />
+ ) : (
+
+
+ ) : undefined
+ }
+ label={
+ Array.isArray(text) && text.length > 0 && Array.isArray(text[0]) ? (
+
+ ) : (
+
+ )
+ }
+ sx={{
+ ...chipStyle,
+ "& .MuiChip-icon": {
+ marginRight: "-7px",
+ },
+ "& .MuiChip-label": {
+ marginBottom: "1px",
+ },
+ "& .MuiInput-input:focus": {
+ backgroundColor: "inherit",
+ },
+ }}
+ variant={variant as "filled" | "outlined" | undefined}
+ >
+
+ )}
+
+ );
+};
+
+export default PillBadge;
diff --git a/app/packages/components/src/components/PillBadge/index.ts b/app/packages/components/src/components/PillBadge/index.ts
new file mode 100644
index 0000000000..45ed630ea2
--- /dev/null
+++ b/app/packages/components/src/components/PillBadge/index.ts
@@ -0,0 +1 @@
+export { default as PillBadge } from "./PillBadge";
diff --git a/app/packages/core/src/plugins/SchemaIO/components/PillBadgeView.tsx b/app/packages/core/src/plugins/SchemaIO/components/PillBadgeView.tsx
new file mode 100644
index 0000000000..787fabbd7d
--- /dev/null
+++ b/app/packages/core/src/plugins/SchemaIO/components/PillBadgeView.tsx
@@ -0,0 +1,22 @@
+import { Box } from "@mui/material";
+import React from "react";
+import { getComponentProps } from "../utils";
+import PillBadge from "@fiftyone/components/src/components/PillBadge/PillBadge";
+
+export default function PillBadgeView(props) {
+ const { schema } = props;
+ const { view = {} } = schema;
+ const { text, color, variant, showIcon } = view;
+
+ return (
+
+
+
+ );
+}
diff --git a/app/packages/core/src/plugins/SchemaIO/components/index.ts b/app/packages/core/src/plugins/SchemaIO/components/index.ts
index bb0fca6f6e..fefdc1c759 100644
--- a/app/packages/core/src/plugins/SchemaIO/components/index.ts
+++ b/app/packages/core/src/plugins/SchemaIO/components/index.ts
@@ -49,3 +49,4 @@ export { default as TextFieldView } from "./TextFieldView";
export { default as TupleView } from "./TupleView";
export { default as UnsupportedView } from "./UnsupportedView";
export { default as FrameLoaderView } from "./FrameLoaderView";
+export { default as PillBadgeView } from "./PillBadgeView";
diff --git a/fiftyone/operators/types.py b/fiftyone/operators/types.py
index 8a630191f2..3a9a47726c 100644
--- a/fiftyone/operators/types.py
+++ b/fiftyone/operators/types.py
@@ -1478,6 +1478,20 @@ def __init__(self, **kwargs):
super().__init__(**kwargs)
+class PillBadgeView(ReadOnlyView):
+ """Displays a pill shaped badge.
+
+ Args:
+ text ("Reviewed" | ["Reviewed", "Not Reviewed"] | [["Not Started", "primary"], ["Reviewed", "success"], ["In Review", "warning"]): a label or set of label options with or without a color for the pill badge
+ color ("primary"): the color of the pill
+ variant ("outlined"): the variant of the pill
+ show_icon (False | True): whether to display indicator icon
+ """
+
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
+
+
class PlotlyView(View):
"""Displays a Plotly chart.