diff --git a/packages/comet-uswds/src/components/step-indicator/step-indicator.tsx b/packages/comet-uswds/src/components/step-indicator/step-indicator.tsx
index 0d9373b9..29026492 100644
--- a/packages/comet-uswds/src/components/step-indicator/step-indicator.tsx
+++ b/packages/comet-uswds/src/components/step-indicator/step-indicator.tsx
@@ -76,7 +76,7 @@ export const StepIndicator = ({
}
return (
-
+
{step}
{segmentSrLabel !== '' && {segmentSrLabel}}
diff --git a/packages/comet-uswds/src/components/table/table.stories.tsx b/packages/comet-uswds/src/components/table/table.stories.tsx
index e2512558..89bd3fef 100644
--- a/packages/comet-uswds/src/components/table/table.stories.tsx
+++ b/packages/comet-uswds/src/components/table/table.stories.tsx
@@ -24,6 +24,7 @@ const Template: StoryFn = (args: TableProps) => {
{
id: 'estimatedPopulation',
name: 'Estimated population at time of admission',
+ sortable: false,
},
];
@@ -84,6 +85,7 @@ const Template: StoryFn = (args: TableProps) => {
sortable={args.sortable}
sortDir={args.sortDir}
sortIndex={args.sortIndex}
+ onSort={args.onSort}
/>
);
};
@@ -100,3 +102,19 @@ Default.args = {
sortDir: 'ascending',
sortIndex: 0,
};
+
+export const OnSort = Template.bind({});
+OnSort.args = {
+ id: 'table-1',
+ tabIndex: 1,
+ caption: 'Voter Data',
+ borderless: false,
+ striped: false,
+ scrollable: false,
+ sortable: true,
+ sortDir: 'ascending',
+ sortIndex: 0,
+ onSort: () => {
+ console.log('Sorting...');
+ },
+};
diff --git a/packages/comet-uswds/src/components/table/table.test.tsx b/packages/comet-uswds/src/components/table/table.test.tsx
index eba79024..b72dbb4f 100644
--- a/packages/comet-uswds/src/components/table/table.test.tsx
+++ b/packages/comet-uswds/src/components/table/table.test.tsx
@@ -1,4 +1,4 @@
-import { fireEvent, render } from '@testing-library/react';
+import { act, fireEvent, render } from '@testing-library/react';
import { axe } from 'jest-axe';
import Table, { TableColumn } from './table';
@@ -142,6 +142,19 @@ describe('Table', () => {
expect(th[0].getAttribute('aria-sort')).toBeNull();
});
+ test('should render a custom sortable table successfully', () => {
+ const customColumns = columns.map((column, index) => ({
+ ...column,
+ sortable: index === 0 ? false : true,
+ }));
+
+ const { baseElement } = render(
+ ,
+ );
+ const th = baseElement.querySelectorAll('th');
+ expect(th[0].getAttribute('aria-sort')).toBeNull();
+ });
+
test('should render a descending sortable table successfully', () => {
const { baseElement } = render(
{
expect(th[0].getAttribute('aria-sort')).not.toBeNull();
});
+ test('should call onSort function when sorting', async () => {
+ const onSort = vi.fn();
+ const { baseElement } = render(
+ ,
+ );
+ expect(onSort).not.toHaveBeenCalled();
+
+ const th = baseElement.querySelectorAll('th')[0];
+ const thButton = th?.querySelector('button') as Element;
+ await act(async () => {
+ fireEvent.click(thButton);
+ });
+ expect(onSort).toHaveBeenCalled();
+ });
+
describe('sorted table', () => {
test('should match data before sorting', () => {
const { baseElement } = render(
diff --git a/packages/comet-uswds/src/components/table/table.tsx b/packages/comet-uswds/src/components/table/table.tsx
index 6785b499..b0f90d89 100644
--- a/packages/comet-uswds/src/components/table/table.tsx
+++ b/packages/comet-uswds/src/components/table/table.tsx
@@ -31,6 +31,10 @@ export interface TableProps {
* The default sort direction if sortIndex is provided
*/
sortDir?: 'ascending' | 'descending';
+ /**
+ * A function to call when the table is sorted
+ */
+ onSort?: () => void;
/**
* A boolean indicating if the table is scrollable or not
*/
@@ -56,6 +60,7 @@ export interface TableProps {
export interface TableColumn {
id: string;
name: string;
+ sortable?: boolean;
}
export interface TableCell {
@@ -74,6 +79,7 @@ export const Table = ({
sortable = false,
sortIndex = 0,
sortDir = 'ascending',
+ onSort,
scrollable = false,
borderless = false,
striped = false,
@@ -99,6 +105,26 @@ export const Table = ({
};
});
+ // If onSort, add a MutationObserver to listen for changes in aria-sort
+ useEffect(() => {
+ const callback = (mutationsList: MutationRecord[]) => {
+ for (const mutation of mutationsList) {
+ if (onSort && mutation.attributeName === 'aria-sort') {
+ const currentSortValue = (mutation.target as HTMLElement).getAttribute('aria-sort');
+ if (currentSortValue) {
+ onSort();
+ }
+ }
+ }
+ };
+
+ const observer = new MutationObserver(callback);
+ if (tableRef.current && onSort) {
+ const tableHeaders = tableRef.current.querySelectorAll('th');
+ tableHeaders.forEach((th) => observer.observe(th, { attributes: true }));
+ }
+ }, [columns]);
+
return (
{caption}
- {columns.map((column: TableColumn, index: number) => (
-
- {column.name}
- |
- ))}
+ {columns
+ .map((obj) => ({
+ ...obj,
+ sortable: obj.sortable !== undefined ? obj.sortable : true,
+ }))
+ .map((column: TableColumn, index: number) => (
+
+ {column.name}
+ |
+ ))}