diff --git a/app/assets/javascripts/members/components/placeholders/app.vue b/app/assets/javascripts/members/components/placeholders/app.vue
new file mode 100644
index 0000000000000000000000000000000000000000..200eaf6efbc25dfeefba29d86308243b2f7686b6
--- /dev/null
+++ b/app/assets/javascripts/members/components/placeholders/app.vue
@@ -0,0 +1,42 @@
+<script>
+import { GlBadge, GlTab, GlTabs } from '@gitlab/ui';
+import { s__ } from '~/locale';
+
+export default {
+  name: 'PlaceholdersTabApp',
+  components: {
+    GlBadge,
+    GlTab,
+    GlTabs,
+  },
+  TABS: [
+    {
+      title: s__('UserMapping|Awaiting reassignment'),
+    },
+    {
+      title: s__('UserMapping|Reassigned'),
+    },
+  ],
+  data() {
+    return {
+      selectedTabIndex: 0,
+    };
+  },
+  methods: {
+    tabCount() {
+      return 0;
+    },
+  },
+};
+</script>
+
+<template>
+  <gl-tabs v-model="selectedTabIndex" class="gl-mt-3">
+    <gl-tab v-for="(tab, index) in $options.TABS" :key="index">
+      <template #title>
+        <span>{{ tab.title }}</span>
+        <gl-badge size="sm" class="gl-tab-counter-badge">{{ tabCount() }}</gl-badge>
+      </template>
+    </gl-tab>
+  </gl-tabs>
+</template>
diff --git a/app/assets/javascripts/members/constants.js b/app/assets/javascripts/members/constants.js
index 2afc9450fc4b1e8e1272eac7ce51e4cca81220e1..40efeb06862a59775fa3f6fa11e3aef3f2044b22 100644
--- a/app/assets/javascripts/members/constants.js
+++ b/app/assets/javascripts/members/constants.js
@@ -3,6 +3,8 @@ import { GlFilteredSearchToken } from '@gitlab/ui';
 import { __, s__ } from '~/locale';
 import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
 
+import PlaceholdersTabApp from './components/placeholders/app.vue';
+
 // Overridden in EE
 export const EE_GROUPS_APP_OPTIONS = {};
 export const EE_PROJECTS_APP_OPTIONS = {};
@@ -166,6 +168,7 @@ export const MEMBER_TYPES = Object.freeze({
   group: 'group',
   invite: 'invite',
   accessRequest: 'accessRequest',
+  placeholder: 'placeholder',
 });
 
 // `app/models/members/group_member.rb`
@@ -178,6 +181,7 @@ export const TAB_QUERY_PARAM_VALUES = Object.freeze({
   group: 'groups',
   invite: 'invited',
   accessRequest: 'access_requests',
+  placeholder: 'placeholders',
 });
 
 // Overridden in EE
@@ -204,6 +208,12 @@ export const TABS = [
     requiredPermissions: ['canManageAccessRequests'],
     queryParamValue: TAB_QUERY_PARAM_VALUES.accessRequest,
   },
+  {
+    namespace: MEMBER_TYPES.placeholder,
+    title: s__('UserMapping|Placeholders'),
+    queryParamValue: TAB_QUERY_PARAM_VALUES.placeholder,
+    component: PlaceholdersTabApp,
+  },
 ];
 
 /**
diff --git a/app/assets/javascripts/members/index.js b/app/assets/javascripts/members/index.js
index 6ca406e359d47988c53661d1e8ea252abd56d89f..73cfe9a30a05959eec399810370e97e949074094 100644
--- a/app/assets/javascripts/members/index.js
+++ b/app/assets/javascripts/members/index.js
@@ -50,6 +50,7 @@ export const initMembersApp = (el, options) => {
 
   return new Vue({
     el,
+    name: 'MembersRoot',
     components: { MembersTabs },
     store,
     apolloProvider: new VueApollo({ defaultClient: createDefaultClient() }),
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index 94f4dfd90b4d286081bb93506dbba53d744b28b9..7b105606793ae9ceb3810c77c9e15d5e57ee298c 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -17,6 +17,7 @@ def self.admin_not_required_endpoints
   before_action :authorize_read_group_member!, only: :index
 
   before_action only: [:index] do
+    push_frontend_feature_flag(:bulk_import_user_mapping, @group)
     push_frontend_feature_flag(:service_accounts_crud, @group)
     push_frontend_feature_flag(:webui_members_inherited_users, current_user)
   end
diff --git a/config/feature_flags/wip/bulk_import_user_mapping.yml b/config/feature_flags/wip/bulk_import_user_mapping.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a882ddfc8e92b3ba050e9178014ccc7d5e845f92
--- /dev/null
+++ b/config/feature_flags/wip/bulk_import_user_mapping.yml
@@ -0,0 +1,9 @@
+---
+name: bulk_import_user_mapping
+feature_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/12378
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/149735
+rollout_issue_url:
+milestone: '17.0'
+group: group::import and integrate
+type: wip
+default_enabled: false
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 6e4b102888dad65a7ab62d3a38cd0b23555eeed0..f9893afab715af0b324effc0a32778f6f105389c 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -55926,6 +55926,15 @@ msgstr ""
 msgid "UserList|created %{timeago}"
 msgstr ""
 
+msgid "UserMapping|Awaiting reassignment"
+msgstr ""
+
+msgid "UserMapping|Placeholders"
+msgstr ""
+
+msgid "UserMapping|Reassigned"
+msgstr ""
+
 msgid "UserProfile|%{count} %{file}"
 msgstr ""
 
diff --git a/spec/frontend/members/components/placeholders/app_spec.js b/spec/frontend/members/components/placeholders/app_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..61a86c50094b9f1b8efdc98eca328d9693d3a024
--- /dev/null
+++ b/spec/frontend/members/components/placeholders/app_spec.js
@@ -0,0 +1,20 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlTabs } from '@gitlab/ui';
+
+import PlaceholdersTabApp from '~/members/components/placeholders/app.vue';
+
+describe('PlaceholdersTabApp', () => {
+  let wrapper;
+
+  const createComponent = () => {
+    wrapper = shallowMount(PlaceholdersTabApp, {});
+  };
+
+  const findTabs = () => wrapper.findComponent(GlTabs);
+
+  it('renders tabs', () => {
+    createComponent();
+
+    expect(findTabs().exists()).toBe(true);
+  });
+});
diff --git a/spec/requests/groups/group_members_controller_spec.rb b/spec/requests/groups/group_members_controller_spec.rb
index 2147090ef51b379e6c72d0cdf1808823175199d9..eae2cdcab00382cdf63ea3c01f8352c5e3fdd783 100644
--- a/spec/requests/groups/group_members_controller_spec.rb
+++ b/spec/requests/groups/group_members_controller_spec.rb
@@ -10,6 +10,20 @@
 
   let(:membershipable_path) { group_path(membershipable) }
 
+  describe 'GET /groups/*group_id/-/group_members' do
+    subject(:request) do
+      get group_group_members_path(group_id: membershipable)
+    end
+
+    it 'pushes feature flag to frontend' do
+      request
+
+      expect(response.body).to have_pushed_frontend_feature_flags(bulkImportUserMapping: true)
+      expect(response.body).to have_pushed_frontend_feature_flags(serviceAccountsCrud: true)
+      expect(response.body).to have_pushed_frontend_feature_flags(webuiMembersInheritedUsers: true)
+    end
+  end
+
   describe 'GET /groups/*group_id/-/group_members/request_access' do
     subject(:request) do
       get request_access_group_group_members_path(group_id: membershipable)