diff --git a/app/assets/javascripts/projects/pipelines/charts/components/app.vue b/app/assets/javascripts/projects/pipelines/charts/components/app.vue
index b48c6d71030640e7d30924384107d9d36154b491..3233eecc2f98b9ea26c3f2efba53b9a0f6195114 100644
--- a/app/assets/javascripts/projects/pipelines/charts/components/app.vue
+++ b/app/assets/javascripts/projects/pipelines/charts/components/app.vue
@@ -21,7 +21,7 @@ export default {
       import('ee_component/dora/components/change_failure_rate_charts.vue'),
     ProjectQualitySummary: () => import('ee_component/project_quality_summary/app.vue'),
   },
-  piplelinesTabEvent: 'p_analytics_ci_cd_pipelines',
+  pipelinesTabEvent: 'p_analytics_ci_cd_pipelines',
   deploymentFrequencyTabEvent: 'p_analytics_ci_cd_deployment_frequency',
   leadTimeTabEvent: 'p_analytics_ci_cd_lead_time',
   timeToRestoreServiceTabEvent: 'visit_ci_cd_time_to_restore_service_tab',
@@ -94,7 +94,7 @@ export default {
       <gl-tab
         :title="__('Pipelines')"
         data-testid="pipelines-tab"
-        @click="trackEvent($options.piplelinesTabEvent)"
+        @click="trackEvent($options.pipelinesTabEvent)"
       >
         <component :is="pipelineChartsComponent" />
       </gl-tab>
diff --git a/app/assets/javascripts/projects/pipelines/charts/components/dashboard_header.vue b/app/assets/javascripts/projects/pipelines/charts/components/dashboard_header.vue
new file mode 100644
index 0000000000000000000000000000000000000000..3a0b1498d73b4c8c2dbb2699cd05236d2d810c28
--- /dev/null
+++ b/app/assets/javascripts/projects/pipelines/charts/components/dashboard_header.vue
@@ -0,0 +1,13 @@
+<script>
+export default {
+  name: 'DashboardHeader',
+};
+</script>
+<template>
+  <div>
+    <h2 class="gl-heading-2 gl-mt-3">
+      <slot></slot>
+    </h2>
+    <slot name="description"></slot>
+  </div>
+</template>
diff --git a/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts.vue b/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts.vue
index 629d3835f72ff251a63d9f8d96bb62fb329d5271..c6d3bc33b6dcedd04e4f7a4082819119ad025386 100644
--- a/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts.vue
+++ b/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts.vue
@@ -20,6 +20,7 @@ import {
 } from '../constants';
 import getPipelineCountByStatus from '../graphql/queries/get_pipeline_count_by_status.query.graphql';
 import getProjectPipelineStatistics from '../graphql/queries/get_project_pipeline_statistics.query.graphql';
+import DashboardHeader from './dashboard_header.vue';
 import StatisticsList from './statistics_list.vue';
 
 const defaultAnalyticsValues = {
@@ -51,6 +52,7 @@ export default {
     GlColumnChart,
     GlChartSeriesLabel,
     GlSkeletonLoader,
+    DashboardHeader,
     StatisticsList,
     CiCdAnalyticsCharts,
   },
@@ -316,9 +318,9 @@ export default {
     <gl-alert v-if="showFailureAlert" :variant="failure.variant" @dismiss="hideAlert">{{
       failure.text
     }}</gl-alert>
-    <div class="gl-mb-3">
-      <h4>{{ s__('PipelineCharts|CI/CD Analytics') }}</h4>
-    </div>
+    <dashboard-header>
+      {{ s__('PipelineCharts|Pipelines') }}
+    </dashboard-header>
     <gl-skeleton-loader v-if="loading" :lines="5" />
     <statistics-list v-else :counts="formattedCounts" />
     <h4>{{ __('Pipelines charts') }}</h4>
diff --git a/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts_new.vue b/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts_new.vue
index 4e72b2d8c8253d6621395a0fbd8fb92f84aaed73..8e3b8b22d6753d5fce2ca589a5ff6d823a8898f8 100644
--- a/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts_new.vue
+++ b/app/assets/javascripts/projects/pipelines/charts/components/pipeline_charts_new.vue
@@ -10,6 +10,7 @@ import {
   DATE_RANGE_LAST_180_DAYS,
 } from '../constants';
 import getPipelineAnalytics from '../graphql/queries/get_pipeline_analytics.query.graphql';
+import DashboardHeader from './dashboard_header.vue';
 import StatisticsList from './statistics_list.vue';
 import PipelineDurationChart from './pipeline_duration_chart.vue';
 import PipelineStatusChart from './pipeline_status_chart.vue';
@@ -18,6 +19,7 @@ export default {
   components: {
     GlCollapsibleListbox,
     GlFormGroup,
+    DashboardHeader,
     StatisticsList,
     PipelineDurationChart,
     PipelineStatusChart,
@@ -106,7 +108,9 @@ export default {
 </script>
 <template>
   <div>
-    <h2>{{ s__('PipelineCharts|Pipelines') }}</h2>
+    <dashboard-header>
+      {{ s__('PipelineCharts|Pipelines') }}
+    </dashboard-header>
     <div class="gl-mb-4 gl-bg-subtle gl-p-4 gl-pb-2">
       <gl-form-group :label="__('Date range')" label-for="date-range">
         <gl-collapsible-listbox
diff --git a/app/views/projects/pipelines/charts.html.haml b/app/views/projects/pipelines/charts.html.haml
index 706886d7b3166bab390f264fb8063fe8f36d7e4e..87dd209ee529fdad9c918a173116ff35cdbf4e30 100644
--- a/app/views/projects/pipelines/charts.html.haml
+++ b/app/views/projects/pipelines/charts.html.haml
@@ -1,5 +1,7 @@
 - page_title _('CI/CD Analytics')
 
+= render ::Layouts::PageHeadingComponent.new(_("CI/CD Analytics"))
+
 #js-project-pipelines-charts-app{ data: { project_path: @project.full_path,
   project_id: @project.id,
   should_render_dora_charts: should_render_dora_charts.to_s,
diff --git a/ee/app/assets/javascripts/dora/components/dora_chart_header.vue b/ee/app/assets/javascripts/dora/components/dora_chart_header.vue
index baed9b0854b29cf4ec4fbe79b671a88e97ba856e..41dcdc937a1cee3a99cc6379a4071ec9eadf587c 100644
--- a/ee/app/assets/javascripts/dora/components/dora_chart_header.vue
+++ b/ee/app/assets/javascripts/dora/components/dora_chart_header.vue
@@ -1,5 +1,7 @@
 <script>
 import { GlLink, GlSprintf } from '@gitlab/ui';
+
+import DashboardHeader from '~/projects/pipelines/charts/components/dashboard_header.vue';
 import { environmentTierDocumentationHref } from './static_data/shared';
 
 export default {
@@ -7,6 +9,7 @@ export default {
   components: {
     GlLink,
     GlSprintf,
+    DashboardHeader,
   },
   props: {
     headerText: {
@@ -27,18 +30,24 @@ export default {
 </script>
 <template>
   <div>
-    <h4 class="gl-my-4">{{ headerText }}</h4>
-    <p data-testid="help-text">
-      <gl-sprintf :message="chartDescriptionText">
-        <template #link="{ content }">
-          <gl-link :href="$options.environmentTierDocumentationHref" target="_blank"
-            ><code>{{ content }}</code></gl-link
-          >
-        </template>
-      </gl-sprintf>
-      <gl-link :href="chartDocumentationHref" target="_blank">
-        {{ __('Learn more.') }}
-      </gl-link>
-    </p>
+    <dashboard-header>
+      <template #default>
+        {{ headerText }}
+      </template>
+      <template #description>
+        <p data-testid="help-text">
+          <gl-sprintf :message="chartDescriptionText">
+            <template #link="{ content }">
+              <gl-link :href="$options.environmentTierDocumentationHref" target="_blank"
+                ><code>{{ content }}</code></gl-link
+              >
+            </template>
+          </gl-sprintf>
+          <gl-link :href="chartDocumentationHref" target="_blank">
+            {{ __('Learn more.') }}
+          </gl-link>
+        </p>
+      </template>
+    </dashboard-header>
   </div>
 </template>
diff --git a/ee/spec/frontend/dora/components/dora_charts_header_spec.js b/ee/spec/frontend/dora/components/dora_charts_header_spec.js
index d13cc158a0b30c58d2b113e5e5457263beac94f2..732055513e4272b669ef3373fbbe0cefaf0409de 100644
--- a/ee/spec/frontend/dora/components/dora_charts_header_spec.js
+++ b/ee/spec/frontend/dora/components/dora_charts_header_spec.js
@@ -24,7 +24,7 @@ describe('dora_chart_header.vue', () => {
   });
 
   it('renders the header text', () => {
-    const actualText = wrapper.find('h4').text();
+    const actualText = wrapper.find('h2').text();
 
     expect(actualText).toBe(mockHeaderText);
   });
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index cfb246993706935db12187b5ac98a71e9c512c7f..621c134ccece390bd0e83d5dd536d8361d51de4d 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -42621,9 +42621,6 @@ msgstr ""
 msgid "PipelineCharts|An unknown error occurred while processing CI/CD analytics."
 msgstr ""
 
-msgid "PipelineCharts|CI/CD Analytics"
-msgstr ""
-
 msgid "PipelineCharts|Failure rate"
 msgstr ""
 
diff --git a/spec/frontend/projects/pipelines/charts/components/dashboard_header_spec.js b/spec/frontend/projects/pipelines/charts/components/dashboard_header_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..1ab74a5f32bfc949f3c77debf5e6f60df899ff07
--- /dev/null
+++ b/spec/frontend/projects/pipelines/charts/components/dashboard_header_spec.js
@@ -0,0 +1,30 @@
+import { shallowMount } from '@vue/test-utils';
+import DashboardHeader from '~/projects/pipelines/charts/components/dashboard_header.vue';
+
+describe('DashboardHeader', () => {
+  let wrapper;
+
+  const createComponent = ({ ...options }) => {
+    wrapper = shallowMount(DashboardHeader, { ...options });
+  };
+
+  it('shows heading', () => {
+    createComponent({
+      slots: {
+        default: 'My Heading',
+      },
+    });
+
+    expect(wrapper.find('h2').text()).toBe('My Heading');
+  });
+
+  it('shows description', () => {
+    createComponent({
+      slots: {
+        description: '<p>My Description</p>',
+      },
+    });
+
+    expect(wrapper.find('p').text()).toContain('My Description');
+  });
+});