diff --git a/packages/frosted-ui/.storybook/stories/components/filter-chip.stories.tsx b/packages/frosted-ui/.storybook/stories/components/filter-chip.stories.tsx
new file mode 100644
index 00000000..f6ebbd0f
--- /dev/null
+++ b/packages/frosted-ui/.storybook/stories/components/filter-chip.stories.tsx
@@ -0,0 +1,108 @@
+import type { Meta, StoryObj } from '@storybook/react';
+
+import React from 'react';
+import { FilterChip, Flex } from '../../../src/components';
+import { filterChipPropDefs } from '../../../src/components/filter-chip.props';
+
+const ExampleIcon = ({ size }: { size: number }) => (
+
+);
+
+// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
+const meta = {
+ title: 'Controls/FilterChip',
+ component: FilterChip,
+ parameters: {
+ // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/react/configure/story-layout
+ layout: 'centered',
+ },
+ args: {
+ children: null,
+ },
+ // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
+ tags: ['autodocs'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
+export const Default: Story = {
+ args: {
+ size: filterChipPropDefs.size.default,
+ color: filterChipPropDefs.color.default,
+ },
+ render: (args) => (
+
+
+
+
+ Disabled checked
+
+
+
+ Disabled unchecked
+
+
+ ),
+};
+
+export const Size: Story = {
+ render: (args) => (
+
+
+ Size 1
+
+
+ Size 2
+
+
+ Size 3
+
+
+ ),
+};
+
+export const Color: Story = {
+ render: (args) => (
+
+
+
+ Indigo
+
+
+
+ Cyan
+
+
+
+ Orange
+
+
+
+ Crimson
+
+
+ ),
+};
diff --git a/packages/frosted-ui/src/components/filter-chip.css b/packages/frosted-ui/src/components/filter-chip.css
new file mode 100644
index 00000000..c08c29d6
--- /dev/null
+++ b/packages/frosted-ui/src/components/filter-chip.css
@@ -0,0 +1,117 @@
+.fui-BaseChip {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ flex-shrink: 0;
+ user-select: none;
+ vertical-align: top;
+ color: var(--base-chip-color);
+}
+
+/***************************************************************************************************
+ * *
+ * SIZES *
+ * *
+ ***************************************************************************************************/
+
+.fui-BaseChip {
+ height: var(--base-chip-height);
+ border-radius: var(--radius-thumb);
+}
+
+@breakpoints {
+ .fui-BaseChip {
+ &:where(.fui-r-size-1) {
+ --base-chip-height: var(--space-5);
+ padding-left: var(--space-2);
+ padding-right: var(--space-2);
+
+ gap: var(--space-1);
+ font-size: var(--font-size-1);
+ line-height: var(--line-height-1);
+ letter-spacing: var(--letter-spacing-1);
+ font-weight: var(--font-weight-medium);
+ }
+ &:where(.fui-r-size-2) {
+ --base-chip-height: var(--space-6);
+ padding-left: var(--space-3);
+ padding-right: var(--space-3);
+
+ gap: calc(1.5 * var(--space-1));
+ font-size: var(--font-size-2);
+ line-height: var(--line-height-2);
+ letter-spacing: var(--letter-spacing-2);
+ font-weight: var(--font-weight-medium);
+ }
+ &:where(.fui-r-size-3) {
+ --base-chip-height: var(--space-7);
+ padding-left: var(--space-4);
+ padding-right: var(--space-4);
+
+ gap: var(--space-2);
+ font-size: var(--font-size-3);
+ line-height: var(--line-height-3);
+ letter-spacing: var(--letter-spacing-3);
+ font-weight: var(--font-weight-medium);
+ }
+ }
+}
+
+.fui-BaseChip:where([data-state='unchecked']) {
+ box-shadow: inset 0 0 0 1px var(--gray-a5);
+ --base-chip-color: var(--gray-a12);
+
+ &:where(:hover) {
+ background-color: var(--gray-a2);
+ }
+ &:where(:active) {
+ background-color: var(--gray-a3);
+ }
+
+ &:where(:focus-visible) {
+ outline: 2px solid var(--color-focus-root);
+ outline-offset: -1px;
+ }
+
+ &:where([data-disabled]) {
+ cursor: var(--cursor-disabled);
+ --base-chip-color: var(--gray-a8);
+ box-shadow: inset 0 0 0 1px var(--gray-a4);
+ background-color: transparent;
+ }
+ &:where(:not([data-disabled])) > svg {
+ color: var(--gray-a11);
+ }
+}
+
+.fui-BaseChip:where([data-state='checked']) {
+ --base-chip-color: var(--accent-11);
+ background-color: var(--accent-a3);
+ box-shadow: inset 0 0 0 1px var(--accent-a6);
+
+ &:where(:focus-visible) {
+ outline: 2px solid var(--accent-8);
+ outline-offset: -1px;
+ }
+ @media (hover: hover) {
+ &:where(:hover) {
+ background-color: var(--accent-a4);
+ }
+ }
+
+ &:where(:active) {
+ background-color: var(--accent-a5);
+ }
+
+ &:where([data-disabled]) {
+ cursor: var(--cursor-disabled);
+ --base-chip-color: var(--gray-8);
+ background-color: var(--gray-a3);
+ box-shadow: inset 0 0 0 1px var(--gray-a5);
+ }
+
+ &:where(:not([data-disabled])) > svg {
+ color: var(--accent-10);
+ }
+}
diff --git a/packages/frosted-ui/src/components/filter-chip.props.ts b/packages/frosted-ui/src/components/filter-chip.props.ts
new file mode 100644
index 00000000..dff6517b
--- /dev/null
+++ b/packages/frosted-ui/src/components/filter-chip.props.ts
@@ -0,0 +1,14 @@
+import type { PropDef } from '../helpers';
+import { colorProp } from '../helpers';
+
+const sizes = ['1', '2', '3'] as const;
+
+const filterChipPropDefs = {
+ size: { type: 'enum', values: sizes, default: '2', responsive: true },
+ color: colorProp,
+} satisfies {
+ size: PropDef<(typeof sizes)[number]>;
+ color: typeof colorProp;
+};
+
+export { filterChipPropDefs };
diff --git a/packages/frosted-ui/src/components/filter-chip.tsx b/packages/frosted-ui/src/components/filter-chip.tsx
new file mode 100644
index 00000000..e7565428
--- /dev/null
+++ b/packages/frosted-ui/src/components/filter-chip.tsx
@@ -0,0 +1,62 @@
+'use client';
+
+import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
+import classNames from 'classnames';
+import * as React from 'react';
+import {
+ extractMarginProps,
+ withBreakpoints,
+ withMarginProps,
+} from '../helpers';
+import { filterChipPropDefs } from './filter-chip.props';
+
+import type {
+ GetPropDefTypes,
+ MarginProps,
+ PropsWithoutRefOrColor,
+} from '../helpers';
+
+type FilterChipElement = React.ElementRef;
+type FilterChipOwnProps = GetPropDefTypes;
+interface FilterChipProps
+ extends PropsWithoutRefOrColor,
+ MarginProps,
+ FilterChipOwnProps {
+ children: React.ReactNode;
+}
+
+const FilterChip = React.forwardRef(
+ (props, forwardedRef) => {
+ const { rest: marginRest, ...marginProps } = extractMarginProps(props);
+ const {
+ children,
+ className,
+ style,
+ size = filterChipPropDefs.size.default,
+ color = filterChipPropDefs.color.default,
+ ...checkboxProps
+ } = marginRest;
+
+ return (
+
+ {children}
+
+ );
+ },
+);
+FilterChip.displayName = 'FilterChip';
+
+export { FilterChip };
+export type { FilterChipProps };
diff --git a/packages/frosted-ui/src/components/index.ts b/packages/frosted-ui/src/components/index.ts
index 996585f6..0c3b1c5c 100644
--- a/packages/frosted-ui/src/components/index.ts
+++ b/packages/frosted-ui/src/components/index.ts
@@ -46,6 +46,8 @@ export { DatePicker } from './date-picker';
export * from './date-picker.props';
export { DateRangePicker } from './date-range-picker';
export * from './date-range-picker.props';
+export { FilterChip } from './filter-chip';
+export * from './filter-chip.props';
export { Shine } from './lab/shine';
export {
Select,
diff --git a/packages/frosted-ui/src/styles/index.css b/packages/frosted-ui/src/styles/index.css
index 9d1e253e..5cc6ee36 100644
--- a/packages/frosted-ui/src/styles/index.css
+++ b/packages/frosted-ui/src/styles/index.css
@@ -30,6 +30,7 @@
@import '../components/drawer.css';
@import '../components/dropdown-menu.css';
@import '../components/em.css';
+@import '../components/filter-chip.css';
@import '../components/flex.css';
@import '../components/grid.css';
@import '../components/heading.css';