diff --git a/app/assets/javascripts/usage_quotas/index.js b/app/assets/javascripts/usage_quotas/index.js
index 414fbc717704dc96d5d02816047ce9323b0da656..67cf14b992d8ea4b8540442602c237c9ea804e6a 100644
--- a/app/assets/javascripts/usage_quotas/index.js
+++ b/app/assets/javascripts/usage_quotas/index.js
@@ -28,7 +28,7 @@ export default () => {
     apolloProvider,
     provide: {
       namespaceName,
-      tabs: usageQuotasTabsMetadata,
+      tabs: usageQuotasTabsMetadata.filter(Boolean),
       ...usageQuotasViewProvideData,
     },
     render(createElement) {
diff --git a/ee/app/assets/javascripts/usage_quotas/constants.js b/ee/app/assets/javascripts/usage_quotas/constants.js
index 6c28045bb7e80535d09178fd19df78ae27291f5d..783461e1f57c07a6225a34d92ee23dfcc2625636 100644
--- a/ee/app/assets/javascripts/usage_quotas/constants.js
+++ b/ee/app/assets/javascripts/usage_quotas/constants.js
@@ -4,3 +4,4 @@ export const USAGE_BY_MONTH_HEADER = s__('UsageQuota|Usage by month');
 export const USAGE_BY_PROJECT_HEADER = s__('UsageQuota|Usage by project');
 
 export const PIPELINES_TAB_METADATA_EL_SELECTOR = '#js-pipeline-usage-app';
+export const SEATS_TAB_METADATA_EL_SELECTOR = '#js-seat-usage-app';
diff --git a/ee/app/assets/javascripts/usage_quotas/group_view_metadata.js b/ee/app/assets/javascripts/usage_quotas/group_view_metadata.js
index 51785752c34ee9616fe1e4183754f1e2fc5df038..0d89c3d06838af97ed385abe62372029fd501a8e 100644
--- a/ee/app/assets/javascripts/usage_quotas/group_view_metadata.js
+++ b/ee/app/assets/javascripts/usage_quotas/group_view_metadata.js
@@ -5,18 +5,26 @@ import PipelineUsageApp from './pipelines/components/app.vue';
 import { parseProvideData as parseStorageTabProvideData } from './storage/utils';
 import { parseProvideData as parsePipelinesTabProvideData } from './pipelines/utils';
 import { PIPELINES_TAB_METADATA_EL_SELECTOR } from './constants';
+import { getSeatTabMetadata } from './seats/tab_metadata';
 
 export const usageQuotasViewProvideData = {
   ...parseStorageTabProvideData(document.querySelector(STORAGE_TAB_METADATA_EL_SELECTOR)),
   ...parsePipelinesTabProvideData(document.querySelector(PIPELINES_TAB_METADATA_EL_SELECTOR)),
 };
 
-const pipelineTabMetadata = {
-  title: __('Pipelines'),
-  component: PipelineUsageApp,
-  shouldRender: () => document.querySelector(PIPELINES_TAB_METADATA_EL_SELECTOR),
+const getPipelineTabMetadata = () => {
+  const el = document.querySelector(PIPELINES_TAB_METADATA_EL_SELECTOR);
+
+  if (!el) return false;
+
+  return {
+    title: __('Pipelines'),
+    component: PipelineUsageApp,
+  };
 };
 
-export const usageQuotasTabsMetadata = [pipelineTabMetadata, storageTabMetadata].filter((tab) =>
-  tab.shouldRender(),
-);
+export const usageQuotasTabsMetadata = [
+  getSeatTabMetadata(),
+  getPipelineTabMetadata(),
+  storageTabMetadata,
+];
diff --git a/ee/app/assets/javascripts/usage_quotas/seats/index.js b/ee/app/assets/javascripts/usage_quotas/seats/index.js
index a9898f4ebac60de432c677619d2a1519eab036e4..c54faf69a26c7d69a7ad085bd7602d3d6d65cd9a 100644
--- a/ee/app/assets/javascripts/usage_quotas/seats/index.js
+++ b/ee/app/assets/javascripts/usage_quotas/seats/index.js
@@ -2,61 +2,15 @@ import Vue from 'vue';
 // eslint-disable-next-line no-restricted-imports
 import Vuex from 'vuex';
 import VueApollo from 'vue-apollo';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import SubscriptionSeats from 'ee/usage_quotas/seats/components/subscription_seats.vue';
-import apolloProvider from 'ee/usage_quotas/shared/provider';
-import { writeDataToApolloCache } from 'ee/usage_quotas/seats/graphql/utils';
-import initialStore from './store';
+import { getSeatTabMetadata } from './tab_metadata';
 
 Vue.use(Vuex);
 Vue.use(VueApollo);
 
-export default (containerId = 'js-seat-usage-app') => {
-  const el = document.getElementById(containerId);
+export default () => {
+  const seatTabMetadata = getSeatTabMetadata(true);
 
-  if (!el) {
-    return false;
-  }
+  if (!seatTabMetadata) return false;
 
-  const {
-    fullPath,
-    namespaceId,
-    namespaceName,
-    isPublicNamespace,
-    seatUsageExportPath,
-    addSeatsHref,
-    hasNoSubscription,
-    maxFreeNamespaceSeats,
-    explorePlansPath,
-    enforcementFreeUserCapEnabled,
-  } = el.dataset;
-
-  const store = new Vuex.Store(
-    initialStore({
-      namespaceId,
-      namespaceName,
-      seatUsageExportPath,
-      addSeatsHref,
-      hasNoSubscription: parseBoolean(hasNoSubscription),
-      maxFreeNamespaceSeats: parseInt(maxFreeNamespaceSeats, 10),
-      explorePlansPath,
-      enforcementFreeUserCapEnabled: parseBoolean(enforcementFreeUserCapEnabled),
-    }),
-  );
-
-  return new Vue({
-    el,
-    name: 'SeatsUsageApp',
-    apolloProvider: writeDataToApolloCache(apolloProvider, { subscriptionId: namespaceId }),
-    provide: {
-      explorePlansPath,
-      fullPath,
-      isPublicNamespace: parseBoolean(isPublicNamespace),
-      namespaceId,
-    },
-    store,
-    render(createElement) {
-      return createElement(SubscriptionSeats);
-    },
-  });
+  return new Vue(seatTabMetadata.component);
 };
diff --git a/ee/app/assets/javascripts/usage_quotas/seats/tab_metadata.js b/ee/app/assets/javascripts/usage_quotas/seats/tab_metadata.js
new file mode 100644
index 0000000000000000000000000000000000000000..1f4d0433341cd01ca8fd70b499404a356bc0e3fb
--- /dev/null
+++ b/ee/app/assets/javascripts/usage_quotas/seats/tab_metadata.js
@@ -0,0 +1,93 @@
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import { __ } from '~/locale';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import apolloProvider from '../shared/provider';
+import { SEATS_TAB_METADATA_EL_SELECTOR } from '../constants';
+import { writeDataToApolloCache as writeSeatsDataToApolloCache } from './graphql/utils';
+import initialSeatUsageStore from './store';
+import SeatUsageApp from './components/subscription_seats.vue';
+
+export const parseProvideData = (el) => {
+  const {
+    fullPath,
+    namespaceId,
+    namespaceName,
+    isPublicNamespace,
+    seatUsageExportPath,
+    addSeatsHref,
+    hasNoSubscription,
+    maxFreeNamespaceSeats,
+    explorePlansPath,
+    enforcementFreeUserCapEnabled,
+  } = el.dataset;
+
+  return {
+    fullPath,
+    namespaceId,
+    namespaceName,
+    isPublicNamespace: parseBoolean(isPublicNamespace),
+    seatUsageExportPath,
+    addSeatsHref,
+    hasNoSubscription: parseBoolean(hasNoSubscription),
+    maxFreeNamespaceSeats: parseInt(maxFreeNamespaceSeats, 10),
+    explorePlansPath,
+    enforcementFreeUserCapEnabled: parseBoolean(enforcementFreeUserCapEnabled),
+  };
+};
+
+export const getSeatTabMetadata = (withMountElement = false) => {
+  const el = document.querySelector(SEATS_TAB_METADATA_EL_SELECTOR);
+
+  if (!el) return false;
+
+  const {
+    fullPath,
+    namespaceId,
+    namespaceName,
+    isPublicNamespace,
+    seatUsageExportPath,
+    addSeatsHref,
+    hasNoSubscription,
+    maxFreeNamespaceSeats,
+    explorePlansPath,
+    enforcementFreeUserCapEnabled,
+  } = parseProvideData(el);
+
+  const store = new Vuex.Store(
+    initialSeatUsageStore({
+      namespaceId,
+      namespaceName,
+      seatUsageExportPath,
+      addSeatsHref,
+      hasNoSubscription,
+      maxFreeNamespaceSeats,
+      explorePlansPath,
+      enforcementFreeUserCapEnabled,
+    }),
+  );
+
+  const seatTabMetadata = {
+    title: __('Seats'),
+    component: {
+      name: 'SeatUsageTab',
+      apolloProvider: writeSeatsDataToApolloCache(apolloProvider, { subscriptionId: namespaceId }),
+      provide: {
+        explorePlansPath,
+        fullPath,
+        isPublicNamespace,
+        namespaceId,
+      },
+      store,
+      render(createElement) {
+        return createElement(SeatUsageApp);
+      },
+    },
+  };
+
+  if (withMountElement) {
+    seatTabMetadata.component.el = el;
+  }
+
+  return seatTabMetadata;
+};
diff --git a/ee/app/views/groups/usage_quotas/index.html.haml b/ee/app/views/groups/usage_quotas/index.html.haml
index de463468ee0dba2fe441b57aa70f1a78e4e2d390..921ea1fc0eece978658e3f827e6da55fc859c982 100644
--- a/ee/app/views/groups/usage_quotas/index.html.haml
+++ b/ee/app/views/groups/usage_quotas/index.html.haml
@@ -7,7 +7,16 @@
 - @force_desktop_expanded_sidebar = true
 
 - if Feature.enabled?(:usage_quotas_for_all_editions, @group)
+  = render Namespaces::FreeUserCap::UsageQuotaAlertComponent.new(namespace: @group.root_ancestor,
+    user: current_user,
+    content_class: 'gl-my-3')
+
+  = render Namespaces::FreeUserCap::UsageQuotaTrialAlertComponent.new(namespace: @group.root_ancestor,
+    user: current_user,
+    content_class: 'gl-my-3')
+
   #js-usage-quotas-view{ data: { namespace_name: @group.name } }
+    #js-seat-usage-app{ data: group_seats_usage_quota_app_data(@group) }
     #js-namespace-storage-app{ data: storage_usage_app_data(@group) }
     - if can? current_user, :admin_ci_minutes, @group
       #js-pipeline-usage-app{ data: pipeline_usage_app_data(@group) }