diff --git a/.changeset/quiet-ways-laugh.md b/.changeset/quiet-ways-laugh.md
new file mode 100644
index 000000000..db98d8aee
--- /dev/null
+++ b/.changeset/quiet-ways-laugh.md
@@ -0,0 +1,5 @@
+---
+"@easypost/easy-ui": minor
+---
+
+feat: KebabButton
diff --git a/easy-ui-react/src/DataGrid/ActionsCellContent.module.scss b/easy-ui-react/src/DataGrid/ActionsCellContent.module.scss
index 8a0f303e3..d95b0de94 100644
--- a/easy-ui-react/src/DataGrid/ActionsCellContent.module.scss
+++ b/easy-ui-react/src/DataGrid/ActionsCellContent.module.scss
@@ -4,13 +4,3 @@
display: inline-flex;
gap: design-token("space.1.5");
}
-
-.MenuButton {
- display: inline-flex;
- border-radius: design-token("shape.border_radius.sm");
-}
-
-.open {
- background: design-token("color.primary.700");
- color: design-token("color.neutral.000");
-}
diff --git a/easy-ui-react/src/DataGrid/ActionsCellContent.tsx b/easy-ui-react/src/DataGrid/ActionsCellContent.tsx
index 5706a13bd..5c10fd033 100644
--- a/easy-ui-react/src/DataGrid/ActionsCellContent.tsx
+++ b/easy-ui-react/src/DataGrid/ActionsCellContent.tsx
@@ -1,10 +1,9 @@
-import MoreVertIcon from "@easypost/easy-ui-icons/MoreVert";
import React, { useCallback, useState } from "react";
import { Icon } from "../Icon";
import { Menu } from "../Menu";
import { Text } from "../Text";
-import { classNames } from "../utilities/css";
-import { UnstyledPressButton } from "./UnstyledPressButton";
+import { KebabButton } from "../KebabButton";
+import { UnstyledPressButton } from "../UnstyledButton/UnstyledPressButton";
import { useDataGridRow } from "./context";
import {
ActionRowAction as ActionRowActionType,
@@ -45,14 +44,13 @@ function MenuRowAction({ rowAction }: { rowAction: MenuRowActionType }) {
setIsOpen(isOpen);
}, []);
- const className = classNames(styles.MenuButton, isOpen && styles.open);
return (
diff --git a/easy-ui-react/src/DataGrid/ExpandCellContent.tsx b/easy-ui-react/src/DataGrid/ExpandCellContent.tsx
index a7b2c187c..ff54c1eda 100644
--- a/easy-ui-react/src/DataGrid/ExpandCellContent.tsx
+++ b/easy-ui-react/src/DataGrid/ExpandCellContent.tsx
@@ -2,7 +2,7 @@ import ArrowForwardIos from "@easypost/easy-ui-icons/ArrowForwardIos";
import React, { useCallback } from "react";
import { Icon } from "../Icon";
import { classNames } from "../utilities/css";
-import { UnstyledPressButton } from "./UnstyledPressButton";
+import { UnstyledPressButton } from "../UnstyledButton/UnstyledPressButton";
import { Text } from "../Text";
import styles from "./ExpandCellContent.module.scss";
diff --git a/easy-ui-react/src/KebabButton/KebabButton.mdx b/easy-ui-react/src/KebabButton/KebabButton.mdx
new file mode 100644
index 000000000..59140d5b0
--- /dev/null
+++ b/easy-ui-react/src/KebabButton/KebabButton.mdx
@@ -0,0 +1,20 @@
+import React from "react";
+import { Canvas, Meta, ArgTypes } from "@storybook/blocks";
+import { KebabButton } from "./KebabButton";
+import * as KebabButtonStories from "./KebabButton.stories";
+
+
+
+# KebabButton
+
+A `` is a kebab menu icon button. The icon represents an overflow menu that reveals a list of options or actions related to the current context when clicked.
+
+## Use with Menu
+
+A `` is designed to used as trigger for ``.
+
+
+
+## Properties
+
+
diff --git a/easy-ui-react/src/KebabButton/KebabButton.module.scss b/easy-ui-react/src/KebabButton/KebabButton.module.scss
new file mode 100644
index 000000000..fc3496025
--- /dev/null
+++ b/easy-ui-react/src/KebabButton/KebabButton.module.scss
@@ -0,0 +1,11 @@
+@use "../styles/common" as *;
+
+.KebabButton {
+ display: inline-flex;
+ border-radius: design-token("shape.border_radius.md");
+}
+
+.KebabButton[aria-expanded="true"] {
+ background-color: design-token("color.primary.700");
+ color: design-token("color.neutral.000");
+}
diff --git a/easy-ui-react/src/KebabButton/KebabButton.stories.tsx b/easy-ui-react/src/KebabButton/KebabButton.stories.tsx
new file mode 100644
index 000000000..d8833465c
--- /dev/null
+++ b/easy-ui-react/src/KebabButton/KebabButton.stories.tsx
@@ -0,0 +1,38 @@
+import { action } from "@storybook/addon-actions";
+import { Meta, StoryObj } from "@storybook/react";
+import React from "react";
+import { OverlayLayoutDecorator } from "../utilities/storybook";
+import { Menu } from "../Menu";
+import { KebabButton } from "./KebabButton";
+
+type Story = StoryObj;
+
+const meta: Meta = {
+ title: "Components/Button/KebabButton",
+ component: KebabButton,
+ argTypes: {
+ accessibilityLabel: {
+ control: "text",
+ description: "Optional custom accessibility label describing the action.",
+ },
+ },
+ args: { accessibilityLabel: "Actions" },
+};
+
+export default meta;
+
+export const WithMenu: Story = {
+ render: () => (
+
+ ),
+ decorators: [OverlayLayoutDecorator],
+};
diff --git a/easy-ui-react/src/KebabButton/KebabButton.test.tsx b/easy-ui-react/src/KebabButton/KebabButton.test.tsx
new file mode 100644
index 000000000..96c0b3e77
--- /dev/null
+++ b/easy-ui-react/src/KebabButton/KebabButton.test.tsx
@@ -0,0 +1,11 @@
+import React from "react";
+import { render, screen } from "@testing-library/react";
+import { KebabButton } from "./KebabButton";
+
+describe("", () => {
+ it("should render a button with icon", () => {
+ render();
+ expect(screen.getByRole("button")).toBeInTheDocument();
+ expect(screen.getByRole("img", { hidden: true })).toBeInTheDocument();
+ });
+});
diff --git a/easy-ui-react/src/KebabButton/KebabButton.tsx b/easy-ui-react/src/KebabButton/KebabButton.tsx
new file mode 100644
index 000000000..6e0c52ec0
--- /dev/null
+++ b/easy-ui-react/src/KebabButton/KebabButton.tsx
@@ -0,0 +1,39 @@
+import React from "react";
+import MoreVertIcon from "@easypost/easy-ui-icons/MoreVert";
+import { AriaButtonProps } from "react-aria";
+import { UnstyledPressButton } from "../UnstyledButton/UnstyledPressButton";
+import { Text } from "../Text";
+import { Icon } from "../Icon";
+import styles from "./KebabButton.module.scss";
+
+export type KebabButtonProps = AriaButtonProps & {
+ /** Optional custom accessibility label describing the action. */
+ accessibilityLabel?: string;
+};
+
+/**
+ * Typically used as a trigger to display a set of options
+ * for the user to choose from.
+ *
+ * @remarks
+ * Can be used alongside Easy UI's `` as the trigger
+ * element.
+ */
+export const KebabButton = React.forwardRef(
+ (props, inRef) => {
+ const { accessibilityLabel = "Actions", ...restProps } = props;
+
+ return (
+
+ {accessibilityLabel}
+
+
+ );
+ },
+);
+
+KebabButton.displayName = "KebabButton";
diff --git a/easy-ui-react/src/KebabButton/index.ts b/easy-ui-react/src/KebabButton/index.ts
new file mode 100644
index 000000000..388964dc2
--- /dev/null
+++ b/easy-ui-react/src/KebabButton/index.ts
@@ -0,0 +1 @@
+export * from "./KebabButton";
diff --git a/easy-ui-react/src/DataGrid/UnstyledPressButton.module.scss b/easy-ui-react/src/UnstyledButton/UnstyledPressButton.module.scss
similarity index 100%
rename from easy-ui-react/src/DataGrid/UnstyledPressButton.module.scss
rename to easy-ui-react/src/UnstyledButton/UnstyledPressButton.module.scss
diff --git a/easy-ui-react/src/DataGrid/UnstyledPressButton.tsx b/easy-ui-react/src/UnstyledButton/UnstyledPressButton.tsx
similarity index 100%
rename from easy-ui-react/src/DataGrid/UnstyledPressButton.tsx
rename to easy-ui-react/src/UnstyledButton/UnstyledPressButton.tsx