diff --git a/app/assets/javascripts/vue_shared/components/resizable_chart/constants.js b/app/assets/javascripts/vue_shared/components/resizable_chart/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..edc5ffb7b77e2711ed0feb356b0f441ba28a263e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/resizable_chart/constants.js
@@ -0,0 +1,6 @@
+export const DEFAULT_RX = 0.4;
+export const DEFAULT_BAR_WIDTH = 6;
+export const DEFAULT_LABEL_WIDTH = 4;
+export const DEFAULT_LABEL_HEIGHT = 5;
+export const BAR_HEIGHTS = [5, 7, 9, 14, 21, 35, 50, 80];
+export const GRID_YS = [30, 60, 90];
diff --git a/app/assets/javascripts/vue_shared/components/resizable_chart/skeleton_loader.vue b/app/assets/javascripts/vue_shared/components/resizable_chart/skeleton_loader.vue
new file mode 100644
index 0000000000000000000000000000000000000000..306fa61780f74587328e1cd393079c606c983235
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/resizable_chart/skeleton_loader.vue
@@ -0,0 +1,95 @@
+<script>
+import { GlSkeletonLoader } from '@gitlab/ui';
+
+import {
+  DEFAULT_RX,
+  DEFAULT_BAR_WIDTH,
+  DEFAULT_LABEL_WIDTH,
+  DEFAULT_LABEL_HEIGHT,
+  BAR_HEIGHTS,
+  GRID_YS,
+} from './constants';
+
+export default {
+  components: {
+    GlSkeletonLoader,
+  },
+  props: {
+    barWidth: {
+      type: Number,
+      default: DEFAULT_BAR_WIDTH,
+      required: false,
+    },
+    labelWidth: {
+      type: Number,
+      default: DEFAULT_LABEL_WIDTH,
+      required: false,
+    },
+    labelHeight: {
+      type: Number,
+      default: DEFAULT_LABEL_HEIGHT,
+      required: false,
+    },
+    rx: {
+      type: Number,
+      default: DEFAULT_RX,
+      required: false,
+    },
+    // skeleton-loader will generate a unique key if not defined
+    uniqueKey: {
+      type: String,
+      default: undefined,
+      required: false,
+    },
+  },
+  computed: {
+    labelCentering() {
+      return (this.barWidth - this.labelWidth) / 2;
+    },
+  },
+  methods: {
+    getBarXPosition(index) {
+      const numberOfBars = this.$options.BAR_HEIGHTS.length;
+      const numberOfSpaces = numberOfBars + 1;
+      const spaceBetweenBars = (100 - numberOfSpaces * this.barWidth) / numberOfBars;
+
+      return (0.5 + index) * (this.barWidth + spaceBetweenBars);
+    },
+  },
+  BAR_HEIGHTS,
+  GRID_YS,
+};
+</script>
+<template>
+  <gl-skeleton-loader :unique-key="uniqueKey">
+    <rect
+      v-for="(y, index) in $options.GRID_YS"
+      :key="`grid-${index}`"
+      data-testid="skeleton-chart-grid"
+      x="0"
+      :y="`${y}%`"
+      width="100%"
+      height="1px"
+    />
+    <rect
+      v-for="(height, index) in $options.BAR_HEIGHTS"
+      :key="`bar-${index}`"
+      data-testid="skeleton-chart-bar"
+      :x="`${getBarXPosition(index)}%`"
+      :y="`${90 - height}%`"
+      :width="`${barWidth}%`"
+      :height="`${height}%`"
+      :rx="`${rx}%`"
+    />
+    <rect
+      v-for="(height, index) in $options.BAR_HEIGHTS"
+      :key="`label-${index}`"
+      data-testid="skeleton-chart-label"
+      :x="`${labelCentering + getBarXPosition(index)}%`"
+      :y="`${100 - labelHeight}%`"
+      :width="`${labelWidth}%`"
+      :height="`${labelHeight}%`"
+      :rx="`${rx}%`"
+    />
+  </gl-skeleton-loader>
+</template>
diff --git a/spec/frontend/vue_shared/components/__snapshots__/resizable_chart_container_spec.js.snap b/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap
similarity index 100%
rename from spec/frontend/vue_shared/components/__snapshots__/resizable_chart_container_spec.js.snap
rename to spec/frontend/vue_shared/components/resizable_chart/__snapshots__/resizable_chart_container_spec.js.snap
diff --git a/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/skeleton_loader_spec.js.snap b/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/skeleton_loader_spec.js.snap
new file mode 100644
index 0000000000000000000000000000000000000000..103b53cb2800fce5dbe34974372103f410e8fb6a
--- /dev/null
+++ b/spec/frontend/vue_shared/components/resizable_chart/__snapshots__/skeleton_loader_spec.js.snap
@@ -0,0 +1,324 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Resizable Skeleton Loader default setup renders the bars, labels, and grid with correct position, size, and rx percentages 1`] = `
+<gl-skeleton-loader-stub
+  baseurl=""
+  height="130"
+  preserveaspectratio="xMidYMid meet"
+  width="400"
+>
+  <rect
+    data-testid="skeleton-chart-grid"
+    height="1px"
+    width="100%"
+    x="0"
+    y="30%"
+  />
+  <rect
+    data-testid="skeleton-chart-grid"
+    height="1px"
+    width="100%"
+    x="0"
+    y="60%"
+  />
+  <rect
+    data-testid="skeleton-chart-grid"
+    height="1px"
+    width="100%"
+    x="0"
+    y="90%"
+  />
+   
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="5%"
+    rx="0.4%"
+    width="6%"
+    x="5.875%"
+    y="85%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="7%"
+    rx="0.4%"
+    width="6%"
+    x="17.625%"
+    y="83%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="9%"
+    rx="0.4%"
+    width="6%"
+    x="29.375%"
+    y="81%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="14%"
+    rx="0.4%"
+    width="6%"
+    x="41.125%"
+    y="76%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="21%"
+    rx="0.4%"
+    width="6%"
+    x="52.875%"
+    y="69%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="35%"
+    rx="0.4%"
+    width="6%"
+    x="64.625%"
+    y="55%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="50%"
+    rx="0.4%"
+    width="6%"
+    x="76.375%"
+    y="40%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="80%"
+    rx="0.4%"
+    width="6%"
+    x="88.125%"
+    y="10%"
+  />
+   
+  <rect
+    data-testid="skeleton-chart-label"
+    height="5%"
+    rx="0.4%"
+    width="4%"
+    x="6.875%"
+    y="95%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="5%"
+    rx="0.4%"
+    width="4%"
+    x="18.625%"
+    y="95%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="5%"
+    rx="0.4%"
+    width="4%"
+    x="30.375%"
+    y="95%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="5%"
+    rx="0.4%"
+    width="4%"
+    x="42.125%"
+    y="95%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="5%"
+    rx="0.4%"
+    width="4%"
+    x="53.875%"
+    y="95%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="5%"
+    rx="0.4%"
+    width="4%"
+    x="65.625%"
+    y="95%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="5%"
+    rx="0.4%"
+    width="4%"
+    x="77.375%"
+    y="95%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="5%"
+    rx="0.4%"
+    width="4%"
+    x="89.125%"
+    y="95%"
+  />
+</gl-skeleton-loader-stub>
+`;
+
+exports[`Resizable Skeleton Loader with custom settings renders the correct position, and size percentages for bars and labels with different settings 1`] = `
+<gl-skeleton-loader-stub
+  baseurl=""
+  height="130"
+  preserveaspectratio="xMidYMid meet"
+  uniquekey=""
+  width="400"
+>
+  <rect
+    data-testid="skeleton-chart-grid"
+    height="1px"
+    width="100%"
+    x="0"
+    y="30%"
+  />
+  <rect
+    data-testid="skeleton-chart-grid"
+    height="1px"
+    width="100%"
+    x="0"
+    y="60%"
+  />
+  <rect
+    data-testid="skeleton-chart-grid"
+    height="1px"
+    width="100%"
+    x="0"
+    y="90%"
+  />
+   
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="5%"
+    rx="0.6%"
+    width="3%"
+    x="6.0625%"
+    y="85%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="7%"
+    rx="0.6%"
+    width="3%"
+    x="18.1875%"
+    y="83%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="9%"
+    rx="0.6%"
+    width="3%"
+    x="30.3125%"
+    y="81%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="14%"
+    rx="0.6%"
+    width="3%"
+    x="42.4375%"
+    y="76%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="21%"
+    rx="0.6%"
+    width="3%"
+    x="54.5625%"
+    y="69%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="35%"
+    rx="0.6%"
+    width="3%"
+    x="66.6875%"
+    y="55%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="50%"
+    rx="0.6%"
+    width="3%"
+    x="78.8125%"
+    y="40%"
+  />
+  <rect
+    data-testid="skeleton-chart-bar"
+    height="80%"
+    rx="0.6%"
+    width="3%"
+    x="90.9375%"
+    y="10%"
+  />
+   
+  <rect
+    data-testid="skeleton-chart-label"
+    height="2%"
+    rx="0.6%"
+    width="7%"
+    x="4.0625%"
+    y="98%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="2%"
+    rx="0.6%"
+    width="7%"
+    x="16.1875%"
+    y="98%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="2%"
+    rx="0.6%"
+    width="7%"
+    x="28.3125%"
+    y="98%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="2%"
+    rx="0.6%"
+    width="7%"
+    x="40.4375%"
+    y="98%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="2%"
+    rx="0.6%"
+    width="7%"
+    x="52.5625%"
+    y="98%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="2%"
+    rx="0.6%"
+    width="7%"
+    x="64.6875%"
+    y="98%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="2%"
+    rx="0.6%"
+    width="7%"
+    x="76.8125%"
+    y="98%"
+  />
+  <rect
+    data-testid="skeleton-chart-label"
+    height="2%"
+    rx="0.6%"
+    width="7%"
+    x="88.9375%"
+    y="98%"
+  />
+</gl-skeleton-loader-stub>
+`;
diff --git a/spec/frontend/vue_shared/components/resizable_chart_container_spec.js b/spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js
similarity index 100%
rename from spec/frontend/vue_shared/components/resizable_chart_container_spec.js
rename to spec/frontend/vue_shared/components/resizable_chart/resizable_chart_container_spec.js
diff --git a/spec/frontend/vue_shared/components/resizable_chart/skeleton_loader_spec.js b/spec/frontend/vue_shared/components/resizable_chart/skeleton_loader_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..7facd02e5960a593531e4e445ed2e9145af58e0a
--- /dev/null
+++ b/spec/frontend/vue_shared/components/resizable_chart/skeleton_loader_spec.js
@@ -0,0 +1,55 @@
+import { shallowMount } from '@vue/test-utils';
+import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
+
+describe('Resizable Skeleton Loader', () => {
+  let wrapper;
+
+  const createComponent = (propsData = {}) => {
+    wrapper = shallowMount(ChartSkeletonLoader, {
+      propsData,
+    });
+  };
+
+  const verifyElementsPresence = () => {
+    const gridItems = wrapper.findAll('[data-testid="skeleton-chart-grid"]').wrappers;
+    const barItems = wrapper.findAll('[data-testid="skeleton-chart-bar"]').wrappers;
+    const labelItems = wrapper.findAll('[data-testid="skeleton-chart-label"]').wrappers;
+    expect(gridItems.length).toBe(3);
+    expect(barItems.length).toBe(8);
+    expect(labelItems.length).toBe(8);
+  };
+
+  afterEach(() => {
+    if (wrapper?.destroy) {
+      wrapper.destroy();
+    }
+  });
+
+  describe('default setup', () => {
+    beforeEach(() => {
+      createComponent({ uniqueKey: null });
+    });
+
+    it('renders the bars, labels, and grid with correct position, size, and rx percentages', () => {
+      expect(wrapper.element).toMatchSnapshot();
+    });
+
+    it('renders the correct number of grid items, bars, and labels', () => {
+      verifyElementsPresence();
+    });
+  });
+
+  describe('with custom settings', () => {
+    beforeEach(() => {
+      createComponent({ uniqueKey: '', rx: 0.6, barWidth: 3, labelWidth: 7, labelHeight: 2 });
+    });
+
+    it('renders the correct position, and size percentages for bars and labels with different settings', () => {
+      expect(wrapper.element).toMatchSnapshot();
+    });
+
+    it('renders the correct number of grid items, bars, and labels', () => {
+      verifyElementsPresence();
+    });
+  });
+});