diff --git a/app/react/components/CollapseExpandButton.test.tsx b/app/react/components/CollapseExpandButton.test.tsx
new file mode 100644
index 000000000..6ea14603d
--- /dev/null
+++ b/app/react/components/CollapseExpandButton.test.tsx
@@ -0,0 +1,68 @@
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+
+import { CollapseExpandButton } from './CollapseExpandButton';
+
+it('should render the button with the correct icon and title', () => {
+ renderCollapseExpandButton();
+ const button = screen.getByRole('button');
+
+ expect(button).toBeInTheDocument();
+ expect(button).toHaveAttribute('title', 'Expand');
+ expect(button).toHaveAttribute('aria-label', 'Expand');
+ expect(button).toHaveAttribute('aria-expanded', 'false');
+ expect(button.querySelector('svg')).toBeInTheDocument();
+});
+
+it('should call the onClick handler when the button is clicked', async () => {
+ const onClick = vi.fn();
+ const { user } = renderCollapseExpandButton({ onClick });
+ const button = screen.getByRole('button');
+
+ await user.click(button);
+
+ expect(onClick).toHaveBeenCalledTimes(1);
+});
+
+it('should prevent default and stop propagation when the button is clicked', async () => {
+ const user = userEvent.setup();
+ const onClick = vi.fn();
+ const onOuterClick = vi.fn();
+
+ render(
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
+
+
+
+ );
+
+ const button = screen.getByLabelText('Expand');
+
+ await user.click(button);
+
+ expect(onOuterClick).not.toHaveBeenCalled();
+ expect(onClick).toHaveBeenCalled();
+});
+
+function renderCollapseExpandButton({
+ isExpanded = false,
+ onClick = vi.fn(),
+}: {
+ isExpanded?: boolean;
+ onClick?(): void;
+} = {}) {
+ const user = userEvent.setup();
+
+ render(
+
+ );
+ return { user };
+}
diff --git a/app/react/components/CollapseExpandButton.tsx b/app/react/components/CollapseExpandButton.tsx
new file mode 100644
index 000000000..3fff465d9
--- /dev/null
+++ b/app/react/components/CollapseExpandButton.tsx
@@ -0,0 +1,41 @@
+import { ChevronDown } from 'lucide-react';
+import { ComponentProps } from 'react';
+import clsx from 'clsx';
+
+import { Icon } from './Icon';
+
+export function CollapseExpandButton({
+ onClick,
+ isExpanded,
+ ...props
+}: { isExpanded: boolean } & ComponentProps<'button'>) {
+ return (
+
+ );
+}
diff --git a/app/react/components/datatables/expand-column.tsx b/app/react/components/datatables/expand-column.tsx
index a4678760e..3f09aaf58 100644
--- a/app/react/components/datatables/expand-column.tsx
+++ b/app/react/components/datatables/expand-column.tsx
@@ -1,7 +1,6 @@
-import { ChevronDown, ChevronUp } from 'lucide-react';
import { ColumnDef } from '@tanstack/react-table';
-import { Button } from '@@/buttons';
+import { CollapseExpandButton } from '../CollapseExpandButton';
import { DefaultType } from './types';
@@ -13,32 +12,25 @@ export function buildExpandColumn(): ColumnDef {
return (
hasExpandableItems && (
-
)
);
},
cell: ({ row }) =>
row.getCanExpand() && (
-