diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php
index 2018f831b3..4baa331411 100644
--- a/src/wp-admin/includes/file.php
+++ b/src/wp-admin/includes/file.php
@@ -2133,7 +2133,9 @@ function wp_print_request_filesystem_credentials_modal() {
  * @return string The HTML for this group and its items.
  */
 function wp_privacy_generate_personal_data_export_group_html( $group_data ) {
-	$group_html  = '<h2>' . esc_html( $group_data['group_label'] ) . '</h2>';
+	$group_label = esc_html( $group_data['group_label'] );
+
+	$group_html  = '<h2 id="' . str_replace( ' ', '_', $group_label ) . '">' . $group_label . '</h2>';
 	$group_html .= '<div>';
 
 	foreach ( (array) $group_data['items'] as $group_item_id => $group_item_data ) {
@@ -2157,6 +2159,10 @@ function wp_privacy_generate_personal_data_export_group_html( $group_data ) {
 		$group_html .= '</table>';
 	}
 
+	$group_html .= '<div class="return_to_table_of_contents">';
+	$group_html .= '<a href="#table_of_contents">' . esc_html__( 'Return to table of contents' ) . '</a>';
+	$group_html .= '</div>';
+
 	$group_html .= '</div>';
 
 	return $group_html;
@@ -2236,6 +2242,8 @@ function wp_privacy_generate_personal_data_export_file( $request_id ) {
 	fwrite( $file, 'th { padding: 5px; text-align: left; width: 20%; }' );
 	fwrite( $file, 'td { padding: 5px; }' );
 	fwrite( $file, 'tr:nth-child(odd) { background-color: #fafafa; }' );
+	fwrite( $file, '#table_of_contents { padding: 10px 0 10px 0; }' );
+	fwrite( $file, '.return_to_table_of_contents { text-align:right; }' );
 	fwrite( $file, '</style>' );
 	fwrite( $file, '<title>' );
 	fwrite( $file, esc_html( $title ) );
@@ -2280,6 +2288,25 @@ function wp_privacy_generate_personal_data_export_file( $request_id ) {
 	// Merge in the special about group.
 	$groups = array_merge( array( 'about' => $about_group ), $groups );
 
+	// Create TOC
+	fwrite( $file, '<div id="table_of_contents">' );
+
+	$group_count = count( $groups );
+
+	foreach ( (array) $groups as $group_id => $group_data ) {
+		$group_label = $group_data['group_label'];
+
+		fwrite( $file, '<a href="#' . str_replace( ' ', '_', $group_label ) . '">' . $group_label . '</a>' );
+
+		if ( $group_count > 1 ) {
+			fwrite( $file, ' | ' );
+		}
+
+		$group_count--;
+	}
+
+	fwrite( $file, '</div>' );
+
 	// Now, iterate over every group in $groups and have the formatter render it in HTML.
 	foreach ( (array) $groups as $group_id => $group_data ) {
 		fwrite( $file, wp_privacy_generate_personal_data_export_group_html( $group_data ) );
