Repository: dhsc-govuk/FingertipsNext
Pull request #599: DHSCFT-808 - Inequalities over time chart and table exports
Author: login: gareth-allan
Created: 2025-05-23T12:37:12Z | Merged: 2025-05-27T13:08:49Z

# Description

Jira ticket: [DHSCFT-808](https://bjss-enterprise.atlassian.net/browse/DHSCFT-808)

Adds support for exporting the inequalities over time chart and table.

## Changes

- Added a `convertInequalitiesTrendTableToCsvData` function to convert inequalities trend table data to CSV
- Call `convertInequalitiesTrendTableToCsvData` from the inequalities line chart table component to generate CSV data
- Added an ExportOptionsButton to the inequalities line chart table component to allow the table to be exported to CSV and PNG

Note: Exporting the inequalities over time chart was already implemented by #585, as line chart component is shared.

## Validation

Tested on http://localhost:3000/chart?si=22401&is=22401&ats=counties-and-unitary-authorities&gts=england&gs=E92000001&ilts=Sex.

### Exporting the chart
#### PNG
![Screenshot 2025-05-23 at 14 51 17](https://github.com/user-attachments/assets/6cdcb03e-ee3d-481a-b249-55a506dafbb1)
Produces the following file:
![inequalitiesLineChart-component](https://github.com/user-attachments/assets/c6205eaa-7e2e-4773-88ad-1c2355cafc9b)

#### SVG
![Screenshot 2025-05-23 at 14 51 29](https://github.com/user-attachments/assets/02c3cdff-abdd-4f57-b1e9-1e8db053b77e)
Produces the following file:
![inequalitiesLineChart-component](https://github.com/user-attachments/assets/6d340650-f12e-4b32-81ee-d639db0bd087)

### Exporting the table
#### PNG
![Screenshot 2025-05-23 at 14 54 21](https://github.com/user-attachments/assets/d5d3a195-4a65-430d-9d0d-bf4ce498cd62)
Produces the following file:
![inequalitiesTrendTable](https://github.com/user-attachments/assets/a8da9900-af69-4a8e-873b-5f459d5ac6ba)

#### CSV
![Screenshot 2025-05-23 at 15 22 18](https://github.com/user-attachments/assets/315643fd-5849-4bd6-aaa2-42f13254a1f9)
Produces the following file:
[inequalitiesTrendTable.csv](https://github.com/user-attachments/files/20412091/inequalitiesTrendTable.csv)


Diff:
diff --git a/frontend/fingertips-frontend/.test/spec/snaps/webkit/fully_integrated_e2e_tests/core_journeys.spec.ts/BOTH-SUBJECT-AND-AREA-then-select-ONE-INDICATOR-and-ONE-AREA-then-check-the-charts-page-inequalitiesLineChartTable-component.png b/frontend/fingertips-frontend/.test/spec/snaps/webkit/fully_integrated_e2e_tests/core_journeys.spec.ts/BOTH-SUBJECT-AND-AREA-then-select-ONE-INDICATOR-and-ONE-AREA-then-check-the-charts-page-inequalitiesLineChartTable-component.png
index bd2df8632..cfcda3dfe 100644
Binary files a/frontend/fingertips-frontend/.test/spec/snaps/webkit/fully_integrated_e2e_tests/core_journeys.spec.ts/BOTH-SUBJECT-AND-AREA-then-select-ONE-INDICATOR-and-ONE-AREA-then-check-the-charts-page-inequalitiesLineChartTable-component.png and b/frontend/fingertips-frontend/.test/spec/snaps/webkit/fully_integrated_e2e_tests/core_journeys.spec.ts/BOTH-SUBJECT-AND-AREA-then-select-ONE-INDICATOR-and-ONE-AREA-then-check-the-charts-page-inequalitiesLineChartTable-component.png differ
diff --git a/frontend/fingertips-frontend/.test/spec/snaps/webkit/fully_integrated_e2e_tests/core_journeys.spec.ts/ONLY-SUBJECT-then-select-ONE-INDICATOR-and-ENGLAND-AREA-then-check-the-charts-page-inequalitiesLineChartTable-component.png b/frontend/fingertips-frontend/.test/spec/snaps/webkit/fully_integrated_e2e_tests/core_journeys.spec.ts/ONLY-SUBJECT-then-select-ONE-INDICATOR-and-ENGLAND-AREA-then-check-the-charts-page-inequalitiesLineChartTable-component.png
index 31ffa17b8..48be34c95 100644
Binary files a/frontend/fingertips-frontend/.test/spec/snaps/webkit/fully_integrated_e2e_tests/core_journeys.spec.ts/ONLY-SUBJECT-then-select-ONE-INDICATOR-and-ENGLAND-AREA-then-check-the-charts-page-inequalitiesLineChartTable-component.png and b/frontend/fingertips-frontend/.test/spec/snaps/webkit/fully_integrated_e2e_tests/core_journeys.spec.ts/ONLY-SUBJECT-then-select-ONE-INDICATOR-and-ENGLAND-AREA-then-check-the-charts-page-inequalitiesLineChartTable-component.png differ
diff --git a/frontend/fingertips-frontend/components/molecules/Inequalities/__snapshots__/barChartHelpers.test.ts.snap b/frontend/fingertips-frontend/components/molecules/Inequalities/BarChart/__snapshots__/barChartHelpers.test.ts.snap
similarity index 100%
rename from frontend/fingertips-frontend/components/molecules/Inequalities/__snapshots__/barChartHelpers.test.ts.snap
rename to frontend/fingertips-frontend/components/molecules/Inequalities/BarChart/__snapshots__/barChartHelpers.test.ts.snap
diff --git a/frontend/fingertips-frontend/components/molecules/Inequalities/barChartHelpers.test.ts b/frontend/fingertips-frontend/components/molecules/Inequalities/BarChart/barChartHelpers.test.ts
similarity index 93%
rename from frontend/fingertips-frontend/components/molecules/Inequalities/barChartHelpers.test.ts
rename to frontend/fingertips-frontend/components/molecules/Inequalities/BarChart/barChartHelpers.test.ts
index 8c18a2c5e..d8af25677 100644
--- a/frontend/fingertips-frontend/components/molecules/Inequalities/barChartHelpers.test.ts
+++ b/frontend/fingertips-frontend/components/molecules/Inequalities/BarChart/barChartHelpers.test.ts
@@ -1,4 +1,4 @@
-import { getBarChartOptions } from './BarChart/barChartHelpers';
+import { getBarChartOptions } from './barChartHelpers';
 
 describe('getBarChartOptions', () => {
   it('should return an object matching the snapshot', () => {
diff --git a/frontend/fingertips-frontend/components/molecules/Inequalities/InequalitiesTrend/index.tsx b/frontend/fingertips-frontend/components/molecules/Inequalities/InequalitiesTrend/index.tsx
index e45edfa90..6d4ffc031 100644
--- a/frontend/fingertips-frontend/components/molecules/Inequalities/InequalitiesTrend/index.tsx
+++ b/frontend/fingertips-frontend/components/molecules/Inequalities/InequalitiesTrend/index.tsx
@@ -44,12 +44,13 @@ import { InequalitiesTypesDropDown } from '../InequalitiesTypesDropDown';
 import { DataSource } from '@/components/atoms/DataSource/DataSource';
 import { StyleChartWrapper } from '@/components/styles/viewPlotStyles/styleChartWrapper';
 import { LineChartVariant } from '@/components/organisms/LineChart/helpers/generateStandardLineChartOptions';
+import { IndicatorDocument } from '@/lib/search/searchTypes';
 
 interface InequalitiesTrendProps {
   healthIndicatorData: HealthDataForArea[];
   searchState: SearchStateParams;
   benchmarkComparisonMethod?: BenchmarkComparisonMethod;
-  measurementUnit?: string;
+  indicatorMetadata?: IndicatorDocument;
   dataSource?: string;
 }
 
@@ -64,7 +65,7 @@ const getBenchmarkOutcomeForYear = (
 
 export function InequalitiesTrend({
   healthIndicatorData,
-  measurementUnit,
+  indicatorMetadata,
   searchState,
   benchmarkComparisonMethod,
   dataSource,
@@ -110,13 +111,17 @@ export function InequalitiesTrend({
     type
   );
 
+  // If the user has made no selection of inequality type to display yet, use
+  // the default inequality category
+  const inequalityType = inequalityTypeSelected ?? inequalityCategories[0];
+
   const filterFunctionGenerator =
     healthDataFilterFunctionGeneratorForInequality[type];
   const healthIndicatorDataWithoutOtherInequalities = {
     ...healthIndicatorData,
     healthData: filterHealthData(
       healthDataForArea.healthData,
-      filterFunctionGenerator(inequalityTypeSelected ?? inequalityCategories[0])
+      filterFunctionGenerator(inequalityType)
     ),
   };
 
@@ -146,6 +151,7 @@ export function InequalitiesTrend({
   if (!yearsDesc.length || allData.length < 2) return null;
 
   const lineChartData: InequalitiesChartData = {
+    areaCode: healthDataForArea.areaCode,
     areaName: healthDataForArea.areaName,
     rowData: allData,
   };
@@ -178,7 +184,7 @@ export function InequalitiesTrend({
         comparisonLabel,
       },
       point.y,
-      measurementUnit
+      indicatorMetadata?.unitLabel
     );
   };
 
@@ -193,7 +199,7 @@ export function InequalitiesTrend({
         areasSelected: areaCodes,
         yAxisTitleText: 'Value',
         xAxisTitleText: 'Period',
-        measurementUnit,
+        measurementUnit: indicatorMetadata?.unitLabel,
         inequalityLineChartAreaSelected,
       }
     );
@@ -233,8 +239,9 @@ export function InequalitiesTrend({
             content: (
               <InequalitiesLineChartTable
                 tableData={lineChartData}
-                measurementUnit={measurementUnit}
+                indicatorMetadata={indicatorMetadata}
                 dynamicKeys={orderedDynamicKeys}
+                inequalityTypeSelected={inequalityType}
               />
             ),
           },
diff --git a/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/__snapshots__/inequalitiesLineChartTable.test.tsx.snap b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/__snapshots__/inequalitiesLineChartTable.test.tsx.snap
index 01ab1dd57..a94298c25 100644
--- a/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/__snapshots__/inequalitiesLineChartTable.test.tsx.snap
+++ b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/__snapshots__/inequalitiesLineChartTable.test.tsx.snap
@@ -114,6 +114,26 @@ exports[`Inequalities table suite snapshot test - should match snapshot 1`] = `
   padding-left: 10px;
 }
 
+@media print {
+
+}
+
+@media only screen and (min-width:641px) {
+
+}
+
+@media only screen and (min-width:641px) {
+
+}
+
+@media only screen and (min-width:641px) {
+
+}
+
+@media only screen and (min-width:641px) {
+
+}
+
 @media print {
   .c1 {
     font-size: 14px;
@@ -174,6 +194,7 @@ exports[`Inequalities table suite snapshot test - should match snapshot 1`] = `
   >
     <table
       class="c1"
+      id="inequalitiesTrendTable"
     >
       <thead
         class=""
@@ -285,5 +306,166 @@ exports[`Inequalities table suite snapshot test - should match snapshot 1`] = `
       </tbody>
     </table>
   </div>
+  .c0 {
+  font-family: "nta",Arial,sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  font-weight: 400;
+  font-size: 16px;
+  line-height: 19px;
+  box-sizing: border-box;
+  display: inline-block;
+  position: relative;
+  width: 100%;
+  margin-top: 0;
+  padding: 7px 10px;
+  border: 2px solid transparent;
+  border-radius: 0;
+  color: #ffffff;
+  background-color: #00703c;
+  box-shadow: 0 2px 0 #002413;
+  text-align: center;
+  vertical-align: top;
+  cursor: pointer;
+  -webkit-appearance: none;
+  margin-bottom: 22px;
+}
+
+.c0:focus {
+  outline: 3px solid #ffdd00;
+  outline-offset: 0;
+}
+
+.c0:link,
+.c0:visited,
+.c0:active,
+.c0:hover {
+  color: #ffffff;
+  -webkit-text-decoration: none;
+  text-decoration: none;
+}
+
+.c0::-moz-focus-inner {
+  padding: 0;
+  border: 0;
+}
+
+.c0:hover,
+.c0:focus {
+  background-color: #00572e;
+}
+
+.c0:active {
+  top: 2px;
+  box-shadow: none;
+}
+
+.c0::before {
+  content: "";
+  display: block;
+  position: absolute;
+  top: -2px;
+  right: -2px;
+  bottom: -4px;
+  left: -2px;
+  background: transparent;
+}
+
+.c0:active::before {
+  top: -4px;
+}
+
+.c0:disabled {
+  opacity: 0.5;
+  background: #00703c;
+}
+
+.c0:disabled:hover {
+  background-color: #00703c;
+  cursor: default;
+}
+
+.c0:disabled:focus {
+  outline: none;
+}
+
+.c0:disabled:active {
+  top: 0;
+  box-shadow: 0 2px 0 #002413;
+}
+
+.c0 svg {
+  max-width: 15px;
+}
+
+@media print {
+  .c0 {
+    font-size: 14px;
+    line-height: 19px;
+  }
+}
+
+@media only screen and (min-width:641px) {
+  .c0 {
+    font-size: 19px;
+    line-height: 19px;
+  }
+}
+
+@media only screen and (min-width:641px) {
+  .c0 {
+    width: auto;
+  }
+}
+
+@media only screen and (min-width:641px) {
+  .c0 svg {
+    margin-left: 10px;
+  }
+}
+
+@media only screen and (min-width:641px) {
+  .c0 {
+    margin-bottom: 32px;
+  }
+}
+
+@media print {
+
+}
+
+@media only screen and (min-width:641px) {
+
+}
+
+@media print {
+
+}
+
+@media only screen and (min-width:641px) {
+
+}
+
+@media print {
+
+}
+
+@media only screen and (min-width:641px) {
+
+}
+
+@media print {
+
+}
+
+@media only screen and (min-width:641px) {
+
+}
+
+<button
+    class="c0"
+  >
+    Export options
+  </button>
 </DocumentFragment>
 `;
diff --git a/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/convertInequalitiesTrendTableToCsvData.test.ts b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/convertInequalitiesTrendTableToCsvData.test.ts
new file mode 100644
index 000000000..0d57d9dc8
--- /dev/null
+++ b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/convertInequalitiesTrendTableToCsvData.test.ts
@@ -0,0 +1,201 @@
+import { CsvHeader } from '@/components/molecules/Export/export.types';
+import { convertInequalitiesTrendTableToCsvData } from './convertInequalitiesTrendTableToCsvData';
+import { IndicatorDocument } from '@/lib/search/searchTypes';
+
+describe('convertInequalitiesTrendTableToCsvData', () => {
+  const indicatorId = 41101;
+  const indicatorName =
+    'Emergency readmissions within 30 days of discharge from hospital';
+  const valueUnit = '%';
+  const indicatorMetadata = {
+    indicatorID: indicatorId,
+    indicatorName,
+    unitLabel: valueUnit,
+  } as unknown as IndicatorDocument;
+  const areaCode = 'E12000003';
+  const areaName = 'Yorkshire and the Humber Region';
+  const inequalityCategory = 'Sex';
+  const tableRows = [
+    {
+      period: 2025,
+      inequalities: {
+        Male: { value: 27 },
+        Female: { value: 42 },
+        Persons: { value: 35 },
+      },
+    },
+    {
+      period: 2026,
+      inequalities: {
+        Male: { value: 29 },
+        Female: { value: 47 },
+        Persons: { value: 39 },
+      },
+    },
+  ];
+
+  it('should contain the expected headers in the first row', () => {
+    const csvData = convertInequalitiesTrendTableToCsvData(
+      areaCode,
+      areaName,
+      inequalityCategory,
+      tableRows,
+      indicatorMetadata
+    );
+
+    expect(csvData[0]).toEqual([
+      CsvHeader.IndicatorId,
+      CsvHeader.IndicatorName,
+      CsvHeader.Period,
+      CsvHeader.Area,
+      CsvHeader.AreaCode,
+      CsvHeader.InequalityCategory,
+      CsvHeader.InequalityType,
+      CsvHeader.ValueUnit,
+      CsvHeader.Value,
+    ]);
+  });
+
+  it('should include a row for each inequality value for each period', () => {
+    const csvData = convertInequalitiesTrendTableToCsvData(
+      areaCode,
+      areaName,
+      inequalityCategory,
+      tableRows,
+      indicatorMetadata
+    );
+
+    expect(csvData).toHaveLength(7);
+    expect(csvData).toContainEqual([
+      indicatorId,
+      indicatorName,
+      2025,
+      areaName,
+      areaCode,
+      inequalityCategory,
+      'Male',
+      valueUnit,
+      27,
+    ]);
+    expect(csvData).toContainEqual([
+      indicatorId,
+      indicatorName,
+      2025,
+      areaName,
+      areaCode,
+      inequalityCategory,
+      'Female',
+      valueUnit,
+      42,
+    ]);
+    expect(csvData).toContainEqual([
+      indicatorId,
+      indicatorName,
+      2025,
+      areaName,
+      areaCode,
+      inequalityCategory,
+      'Persons',
+      valueUnit,
+      35,
+    ]);
+    expect(csvData).toContainEqual([
+      indicatorId,
+      indicatorName,
+      2026,
+      areaName,
+      areaCode,
+      inequalityCategory,
+      'Male',
+      valueUnit,
+      29,
+    ]);
+    expect(csvData).toContainEqual([
+      indicatorId,
+      indicatorName,
+      2026,
+      areaName,
+      areaCode,
+      inequalityCategory,
+      'Female',
+      valueUnit,
+      47,
+    ]);
+    expect(csvData).toContainEqual([
+      indicatorId,
+      indicatorName,
+      2026,
+      areaName,
+      areaCode,
+      inequalityCategory,
+      'Persons',
+      valueUnit,
+      39,
+    ]);
+  });
+
+  it('should use an empty field for missing data', () => {
+    const csvData = convertInequalitiesTrendTableToCsvData(
+      areaCode,
+      areaName,
+      inequalityCategory,
+      [
+        {
+          period: 2025,
+          inequalities: {
+            Male: undefined,
+            Female: { value: undefined },
+            Persons: { value: 35 },
+          },
+        },
+      ]
+    );
+
+    expect(csvData).toHaveLength(4);
+    expect(csvData).toContainEqual([
+      undefined,
+      undefined,
+      2025,
+      areaName,
+      areaCode,
+      inequalityCategory,
+      'Male',
+      undefined,
+      undefined,
+    ]);
+    expect(csvData).toContainEqual([
+      undefined,
+      undefined,
+      2025,
+      areaName,
+      areaCode,
+      inequalityCategory,
+      'Female',
+      undefined,
+      undefined,
+    ]);
+    expect(csvData).toContainEqual([
+      undefined,
+      undefined,
+      2025,
+      areaName,
+      areaCode,
+      inequalityCategory,
+      'Persons',
+      undefined,
+      35,
+    ]);
+  });
+
+  it('should throw an error if no data rows are provided', () => {
+    expect(() => {
+      convertInequalitiesTrendTableToCsvData(
+        areaCode,
+        areaName,
+        inequalityCategory,
+        [],
+        indicatorMetadata
+      );
+    }).toThrow();
+  });
+});
diff --git a/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/convertInequalitiesTrendTableToCsvData.ts b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/convertInequalitiesTrendTableToCsvData.ts
new file mode 100644
index 000000000..f3bf55646
--- /dev/null
+++ b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/convertInequalitiesTrendTableToCsvData.ts
@@ -0,0 +1,48 @@
+import { CsvHeader } from '@/components/molecules/Export/export.types';
+import { InequalitiesTableRowData } from '@/components/organisms/Inequalities/inequalitiesHelpers';
+import { CsvData } from '@/lib/downloadHelpers/convertToCsv';
+import { IndicatorDocument } from '@/lib/search/searchTypes';
+
+const headers: CsvHeader[] = [
+  CsvHeader.IndicatorId,
+  CsvHeader.IndicatorName,
+  CsvHeader.Period,
+  CsvHeader.Area,
+  CsvHeader.AreaCode,
+  CsvHeader.InequalityCategory,
+  CsvHeader.InequalityType,
+  CsvHeader.ValueUnit,
+  CsvHeader.Value,
+];
+
+export const convertInequalitiesTrendTableToCsvData = (
+  areaCode: string,
+  areaName: string,
+  inequalityCategory: string,
+  tableRows: InequalitiesTableRowData[],
+  indicatorMetadata?: IndicatorDocument
+): CsvData => {
+  if (tableRows.length < 1) {
+    throw new Error('Invalid data provided.');
+  }
+
+  const convertedRows = tableRows.flatMap((tableRow) => {
+    return Object.entries(tableRow.inequalities).map(
+      ([inequalityType, rowData]) => {
+        return [
+          indicatorMetadata?.indicatorID,
+          indicatorMetadata?.indicatorName,
+          tableRow.period,
+          areaName,
+          areaCode,
+          inequalityCategory,
+          inequalityType,
+          indicatorMetadata?.unitLabel,
+          rowData?.value,
+        ];
+      }
+    );
+  });
+
+  return [headers, ...convertedRows];
+};
diff --git a/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/index.tsx b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/index.tsx
index d9d8d33bd..b993983f6 100644
--- a/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/index.tsx
+++ b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/index.tsx
@@ -14,15 +14,19 @@ import {
   InequalitiesChartData,
 } from '@/components/organisms/Inequalities/inequalitiesHelpers';
 import { ReactNode } from 'react';
+import { convertInequalitiesTrendTableToCsvData } from './convertInequalitiesTrendTableToCsvData';
+import { IndicatorDocument } from '@/lib/search/searchTypes';
+import { ExportOptionsButton } from '@/components/molecules/Export/ExportOptionsButton';
 
 export enum InequalitiesTableHeadingsEnum {
   PERIOD = 'Period',
 }
 
 interface InequalitiesLineChartTableProps {
+  inequalityTypeSelected: string;
+  indicatorMetadata?: IndicatorDocument;
   tableData: InequalitiesChartData;
   dynamicKeys: string[];
-  measurementUnit?: string;
 }
 
 const StyledAlignCenterHeader = styled(StyledTableCellHeader)({
@@ -69,9 +73,10 @@ const getCellHeader = (heading: string, index: number): ReactNode => {
 };
 
 export function InequalitiesLineChartTable({
+  inequalityTypeSelected,
+  indicatorMetadata,
   tableData,
   dynamicKeys,
-  measurementUnit,
 }: Readonly<InequalitiesLineChartTableProps>) {
   const tableHeaders = [
     ...Object.values(InequalitiesTableHeadingsEnum),
@@ -88,48 +93,63 @@ export function InequalitiesLineChartTable({
     (data) => data.period >= firstYear && data.period <= lastYear
   );
 
+  const csvData = convertInequalitiesTrendTableToCsvData(
+    tableData.areaCode,
+    tableData.areaName,
+    inequalityTypeSelected,
+    filteredRowData,
+    indicatorMetadata
+  );
+
   return (
-    <StyledDivWithScrolling data-testid="inequalitiesLineChartTable-component">
-      <Table
-        head={
-          <>
-            <Table.Row>
-              <StyledAlignCenterHeader colSpan={tableHeaders.length}>
-                {tableData.areaName}
-                {measurementUnit ? (
-                  <span
-                    style={{ display: 'block', marginTop: '10px' }}
-                    data-testid="inequalitiesLineChartTable-measurementUnit"
-                  >
-                    Value: {measurementUnit}
-                  </span>
-                ) : null}
-              </StyledAlignCenterHeader>
+    <>
+      <StyledDivWithScrolling data-testid="inequalitiesLineChartTable-component">
+        <Table
+          id="inequalitiesTrendTable"
+          head={
+            <>
+              <Table.Row>
+                <StyledAlignCenterHeader colSpan={tableHeaders.length}>
+                  {tableData.areaName}
+                  {indicatorMetadata?.unitLabel ? (
+                    <span
+                      style={{ display: 'block', marginTop: '10px' }}
+                      data-testid="inequalitiesLineChartTable-measurementUnit"
+                    >
+                      Value: {indicatorMetadata.unitLabel}
+                    </span>
+                  ) : null}
+                </StyledAlignCenterHeader>
+              </Table.Row>
+              <Table.Row>
+                {tableHeaders.map((heading, index) =>
+                  getCellHeader(heading, index)
+                )}
+              </Table.Row>
+            </>
+          }
+        >
+          {filteredRowData.map((data, index) => (
+            <Table.Row key={String(data.period) + index}>
+              <StyledAlignLeftStickyTableCell>
+                {String(data.period)}
+              </StyledAlignLeftStickyTableCell>
+              {dynamicKeys.map((key, index) => (
+                <StyledAlignRightTableCell
+                  key={key + index}
+                  style={{ paddingRight: '10px' }}
+                >
+                  {getDisplayValue(data.inequalities[key]?.value)}
+                </StyledAlignRightTableCell>
+              ))}
             </Table.Row>
-            <Table.Row>
-              {tableHeaders.map((heading, index) =>
-                getCellHeader(heading, index)
-              )}
-            </Table.Row>
-          </>
-        }
-      >
-        {filteredRowData.map((data, index) => (
-          <Table.Row key={String(data.period) + index}>
-            <StyledAlignLeftStickyTableCell>
-              {String(data.period)}
-            </StyledAlignLeftStickyTableCell>
-            {dynamicKeys.map((key, index) => (
-              <StyledAlignRightTableCell
-                key={key + index}
-                style={{ paddingRight: '10px' }}
-              >
-                {getDisplayValue(data.inequalities[key]?.value)}
-              </StyledAlignRightTableCell>
-            ))}
-          </Table.Row>
-        ))}
-      </Table>
-    </StyledDivWithScrolling>
+          ))}
+        </Table>
+      </StyledDivWithScrolling>
+      <ExportOptionsButton
+        targetId={'inequalitiesTrendTable'}
+        csvData={csvData}
+      />
+    </>
   );
 }
diff --git a/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/inequalitiesLineChartTable.test.tsx b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/inequalitiesLineChartTable.test.tsx
index 8f4f8c1bc..96476ae07 100644
--- a/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/inequalitiesLineChartTable.test.tsx
+++ b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/inequalitiesLineChartTable.test.tsx
@@ -3,11 +3,13 @@ import { expect } from '@jest/globals';
 import { InequalitiesLineChartTable } from '.';
 import { MOCK_HEALTH_DATA } from '@/lib/tableHelpers/mocks';
 import { InequalitiesChartData } from '@/components/organisms/Inequalities/inequalitiesHelpers';
+import { IndicatorDocument } from '@/lib/search/searchTypes';
 
 describe('Inequalities table suite', () => {
   const CELLS_PER_ROW = 4;
 
   const tableData: InequalitiesChartData = {
+    areaCode: MOCK_HEALTH_DATA[1].areaCode,
     areaName: MOCK_HEALTH_DATA[1].areaName,
     rowData: [
       {
@@ -34,6 +36,7 @@ describe('Inequalities table suite', () => {
       <InequalitiesLineChartTable
         tableData={tableData}
         dynamicKeys={['Persons', 'Male', 'Female']}
+        inequalityTypeSelected="Sex"
       />
     );
 
@@ -49,6 +52,7 @@ describe('Inequalities table suite', () => {
       <InequalitiesLineChartTable
         tableData={tableData}
         dynamicKeys={['Persons', 'Male', 'Female']}
+        inequalityTypeSelected="Sex"
       />
     );
 
@@ -68,11 +72,13 @@ describe('Inequalities table suite', () => {
         screen.getByTestId(`header-${heading}-${index}`)
       ).toBeInTheDocument()
     );
+    expect(screen.getByRole('button')).toHaveTextContent('Export options');
   });
 
   it('should display x if data point is not available', () => {
     const expectedNumberOfRows = 2;
     const tableData: InequalitiesChartData = {
+      areaCode: MOCK_HEALTH_DATA[1].areaCode,
       areaName: MOCK_HEALTH_DATA[1].areaName,
       rowData: [
         {
@@ -94,6 +100,7 @@ describe('Inequalities table suite', () => {
       <InequalitiesLineChartTable
         tableData={tableData}
         dynamicKeys={['Persons', 'Male', 'Female']}
+        inequalityTypeSelected="Sex"
       />
     );
     expect(screen.getAllByRole('cell')).toHaveLength(
@@ -109,7 +116,11 @@ describe('Inequalities table suite', () => {
     const cellsPerRow = 1;
 
     render(
-      <InequalitiesLineChartTable tableData={tableData} dynamicKeys={[]} />
+      <InequalitiesLineChartTable
+        tableData={tableData}
+        dynamicKeys={[]}
+        inequalityTypeSelected="Sex"
+      />
     );
 
     expect(screen.getByTestId('header-Period-0')).toBeInTheDocument();
@@ -128,7 +139,8 @@ describe('Inequalities table suite', () => {
       <InequalitiesLineChartTable
         tableData={tableData}
         dynamicKeys={['Persons', 'Male', 'Female']}
-        measurementUnit="per 100,000"
+        indicatorMetadata={{ unitLabel: 'per 100,000' } as IndicatorDocument}
+        inequalityTypeSelected="Sex"
       />
     );
     expect(screen.getByText('Value: per 100,000')).toBeInTheDocument();
@@ -139,6 +151,7 @@ describe('Inequalities table suite', () => {
       <InequalitiesLineChartTable
         tableData={tableData}
         dynamicKeys={['Persons', 'Male', 'Female']}
+        inequalityTypeSelected="Sex"
       />
     );
 
@@ -152,7 +165,8 @@ describe('Inequalities table suite', () => {
       <InequalitiesLineChartTable
         tableData={tableData}
         dynamicKeys={['Persons', 'Male', 'Female']}
-        measurementUnit="per 100,000"
+        indicatorMetadata={{ unitLabel: 'per 100,000' } as IndicatorDocument}
+        inequalityTypeSelected="Sex"
       />
     );
     expect(container.asFragment()).toMatchSnapshot();
@@ -186,6 +200,7 @@ describe('Inequalities table suite', () => {
       <InequalitiesLineChartTable
         tableData={tableDataWithExtraYears}
         dynamicKeys={['Persons', 'Male', 'Female']}
+        inequalityTypeSelected="Sex"
       />
     );
 
diff --git a/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/mocks.ts b/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/mocks.ts
deleted file mode 100644
index f36b4cec7..000000000
--- a/frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/mocks.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { InequalitiesChartData } from '@/components/organisms/Inequalities/inequalitiesHelpers';
-import { MOCK_HEALTH_DATA } from '@/lib/tableHelpers/mocks';
-
-export const tableData: InequalitiesChartData = {
-  areaName: MOCK_HEALTH_DATA[1].areaName,
-  rowData: [
-    {
-      period: 2004,
-      inequalities: {
-        Persons: { value: 890.3432 },
-        Male: { value: 703.420759 },
-        Female: { value: 703.420759 },
-      },
-    },
-    {
-      period: 2008,
-      inequalities: {
-        Persons: { value: 135.149304 },
-        Male: { value: 890.328253 },
-        Female: { value: 890.328253 },
-      },
-    },
-  ],
-};
diff --git a/frontend/fingertips-frontend/components/organisms/Inequalities/index.tsx b/frontend/fingertips-frontend/components/organisms/Inequalities/index.tsx
index 08a898d81..78c5ab829 100644
--- a/frontend/fingertips-frontend/components/organisms/Inequalities/index.tsx
+++ b/frontend/fingertips-frontend/components/organisms/Inequalities/index.tsx
@@ -6,10 +6,11 @@ import {
 import { InequalitiesForSingleTimePeriod } from '@/components/molecules/Inequalities/InequalitiesForSingleTimePeriod';
 import { InequalitiesTrend } from '@/components/molecules/Inequalities/InequalitiesTrend';
 import { SearchStateParams } from '@/lib/searchStateManager';
+import { IndicatorDocument } from '@/lib/search/searchTypes';
 
 interface InequalitiesProps {
   healthIndicatorData: HealthDataForArea[];
-  measurementUnit?: string;
+  indicatorMetadata?: IndicatorDocument;
   searchState: SearchStateParams;
   benchmarkComparisonMethod?: BenchmarkComparisonMethod;
   polarity?: IndicatorPolarity;
@@ -18,7 +19,7 @@ interface InequalitiesProps {
 
 export function Inequalities({
   healthIndicatorData,
-  measurementUnit,
+  indicatorMetadata,
   searchState,
   benchmarkComparisonMethod = BenchmarkComparisonMethod.Unknown,
   polarity = IndicatorPolarity.Unknown,
@@ -29,14 +30,14 @@ export function Inequalities({
       <InequalitiesForSingleTimePeriod
         healthIndicatorData={healthIndicatorData}
         searchState={searchState}
-        measurementUnit={measurementUnit}
+        measurementUnit={indicatorMetadata?.unitLabel}
         benchmarkComparisonMethod={benchmarkComparisonMethod}
         polarity={polarity}
         dataSource={dataSource}
       />
       <InequalitiesTrend
         healthIndicatorData={healthIndicatorData}
-        measurementUnit={measurementUnit}
+        indicatorMetadata={indicatorMetadata}
         searchState={searchState}
         benchmarkComparisonMethod={benchmarkComparisonMethod}
         dataSource={dataSource}
diff --git a/frontend/fingertips-frontend/components/organisms/Inequalities/inequalities.test.tsx b/frontend/fingertips-frontend/components/organisms/Inequalities/inequalities.test.tsx
index 1fb4c7f23..59fbeed04 100644
--- a/frontend/fingertips-frontend/components/organisms/Inequalities/inequalities.test.tsx
+++ b/frontend/fingertips-frontend/components/organisms/Inequalities/inequalities.test.tsx
@@ -5,6 +5,7 @@ import { MOCK_HEALTH_DATA } from '@/lib/tableHelpers/mocks';
 import { SearchParams, SearchStateParams } from '@/lib/searchStateManager';
 import { SearchStateContext } from '@/context/SearchStateContext';
 import { LoaderContext } from '@/context/LoaderContext';
+import { IndicatorDocument } from '@/lib/search/searchTypes';
 
 const state: SearchStateParams = {
   [SearchParams.SearchedIndicator]: 'testing',
@@ -101,7 +102,7 @@ describe('Inequalities suite', () => {
       <Inequalities
         healthIndicatorData={MOCK_HEALTH_DATA}
         searchState={state}
-        measurementUnit="kg"
+        indicatorMetadata={{ unitLabel: 'kg' } as IndicatorDocument}
       />
     );
     expect(await screen.findByText('kg')).toBeInTheDocument();
diff --git a/frontend/fingertips-frontend/components/organisms/Inequalities/inequalitiesHelpers.test.ts b/frontend/fingertips-frontend/components/organisms/Inequalities/inequalitiesHelpers.test.ts
index d6e8cb068..44260630c 100644
--- a/frontend/fingertips-frontend/components/organisms/Inequalities/inequalitiesHelpers.test.ts
+++ b/frontend/fingertips-frontend/components/organisms/Inequalities/inequalitiesHelpers.test.ts
@@ -175,7 +175,8 @@ const mockInequalitiesRowData: InequalitiesTableRowData[] = [
   },
 ];
 
-const mockChartData = {
+const mockChartData: InequalitiesChartData = {
+  areaCode: 'A1425',
   areaName: 'North FooBar',
   rowData: [...mockInequalitiesRowData],
 };
@@ -625,6 +626,7 @@ describe('generateLineChartSeriesData', () => {
 
   it('should use the expected styling for deprivation data', () => {
     const mockChartData = {
+      areaCode: 'A1425',
       areaName: 'North FooBar',
       rowData: [
         {
@@ -829,6 +831,7 @@ describe('generateLineChartSeriesData', () => {
   it('should only include years for which the selected areas have data', () => {
     const areasSelected = ['A1'];
     const mockChartDataWithExtraYears: InequalitiesChartData = {
+      areaCode: 'A1425',
       areaName: 'A1',
       rowData: [
         ...mockInequalitiesRowData,
@@ -870,6 +873,7 @@ describe('generateLineChartSeriesData', () => {
   it('should include CIs for aggregate series only for years for which the selected areas have data', () => {
     const areasSelected = ['A1'];
     const mockChartDataWithExtraYears: InequalitiesChartData = {
+      areaCode: 'A1425',
       areaName: 'A1',
       rowData: [
         ...mockInequalitiesRowData,
diff --git a/frontend/fingertips-frontend/components/organisms/Inequalities/inequalitiesHelpers.ts b/frontend/fingertips-frontend/components/organisms/Inequalities/inequalitiesHelpers.ts
index 8c0122e55..cc3495d5c 100644
--- a/frontend/fingertips-frontend/components/organisms/Inequalities/inequalitiesHelpers.ts
+++ b/frontend/fingertips-frontend/components/organisms/Inequalities/inequalitiesHelpers.ts
@@ -37,6 +37,7 @@ type InequalitySequenceSelector = (dataPoint?: HealthDataPoint) => number;
 type HealthDataFilterFunction = (dataPoint: HealthDataPoint) => boolean;
 
 export interface InequalitiesChartData {
+  areaCode: string;
   areaName: string;
   rowData: InequalitiesTableRowData[];
 }
diff --git a/frontend/fingertips-frontend/components/viewPlots/OneIndicatorOneAreaViewPlots/index.tsx b/frontend/fingertips-frontend/components/viewPlots/OneIndicatorOneAreaViewPlots/index.tsx
index fea879f27..afb88f91d 100644
--- a/frontend/fingertips-frontend/components/viewPlots/OneIndicatorOneAreaViewPlots/index.tsx
+++ b/frontend/fingertips-frontend/components/viewPlots/OneIndicatorOneAreaViewPlots/index.tsx
@@ -159,7 +159,7 @@ export function OneIndicatorOneAreaViewPlots({
       <Inequalities
         healthIndicatorData={healthIndicatorData}
         searchState={searchState}
-        measurementUnit={indicatorMetadata?.unitLabel}
+        indicatorMetadata={indicatorMetadata}
         benchmarkComparisonMethod={benchmarkComparisonMethod}
         polarity={polarity}
         dataSource={indicatorMetadata?.dataSource}


Reviews:
user: login: gareth-allan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T12:48:49Z
user: login: gareth-allan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T12:49:19Z
user: login: gareth-allan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T13:22:41Z
user: login: stuc-bjss
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T14:21:15Z

Review comments:
path: frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/mocks.ts
user: login: gareth-allan
body: This file wasn't being used.
created_at: 2025-05-23T12:48:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -88,6 +92,17 @@ export function InequalitiesLineChartTable({
     (data) => data.period >= firstYear && data.period <= lastYear
   );
 
+  const csvData = convertInequalitiesTrendTableToCsvData(
+    tableData.areaCode,
+    tableData.areaName,
+    inequalityTypeSelected,
+    filteredRowData,
+    indicatorMetadata
+  );
+
+  // TODO: Remove this and add the download button
+  console.table(csvData);
path: frontend/fingertips-frontend/components/molecules/Inequalities/LineChart/Table/index.tsx
user: login: gareth-allan
body: To be done before publishing this PR.
created_at: 2025-05-23T12:49:18Z
author_association: CONTRIBUTOR
path: frontend/fingertips-frontend/components/molecules/Inequalities/BarChart/barChartHelpers.test.ts
user: login: gareth-allan
body: This was just in a different location than the file it's testing.
created_at: 2025-05-23T13:22:41Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-05-23T17:18:37Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=dhsc-govuk_FingertipsNext&pullRequest=599) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=dhsc-govuk_FingertipsNext&pullRequest=599&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=dhsc-govuk_FingertipsNext&pullRequest=599&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=dhsc-govuk_FingertipsNext&pullRequest=599&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=dhsc-govuk_FingertipsNext&pullRequest=599&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=dhsc-govuk_FingertipsNext&pullRequest=599&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=dhsc-govuk_FingertipsNext&pullRequest=599)


author_association: NONE