diff --git a/ee/app/components/gitlab_subscriptions/duo_enterprise_alert/base_component.html.haml b/ee/app/components/gitlab_subscriptions/duo_enterprise_alert/base_component.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..5b65c7c21fa522f79fef3df6dc73f9fde6e2ad29
--- /dev/null
+++ b/ee/app/components/gitlab_subscriptions/duo_enterprise_alert/base_component.html.haml
@@ -0,0 +1,13 @@
+= render Pajamas::CardComponent.new(card_options: card_options) do |c|
+  - c.with_body do
+    .gl-text-size-h2.gl-font-bold
+      = icon
+      = title
+    .gl-mb-5
+      - body.map do |line|
+        .gl-mt-3
+          = line
+    .gl-flex.gl-flex-wrap.gl-gap-3
+      = render Pajamas::ButtonComponent.new(**primary_cta_options) do
+        = primary_cta
+      .js-hand-raise-lead-trigger{ data: hand_raise_lead_data }
diff --git a/ee/app/components/gitlab_subscriptions/duo_enterprise_alert/base_component.rb b/ee/app/components/gitlab_subscriptions/duo_enterprise_alert/base_component.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a75a37bf36801006bca58f35191480657cbba52b
--- /dev/null
+++ b/ee/app/components/gitlab_subscriptions/duo_enterprise_alert/base_component.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+module GitlabSubscriptions
+  module DuoEnterpriseAlert
+    class BaseComponent < ViewComponent::Base
+      # @param [Namespace or Group] namespace
+      # @param [User] user
+
+      def initialize(namespace:, user:)
+        @namespace = namespace
+        @user = user
+      end
+
+      private
+
+      attr_reader :namespace, :user
+
+      delegate :sprite_icon, to: :helpers
+
+      def duo_enterprise_trials_enabled?
+        Feature.enabled?(:duo_enterprise_trials, user)
+      end
+
+      def card_options
+        {
+          class: 'gl-border gl-border-blue-300 gl-bg-blue-50 gl-rounded-base gl-text-left gl-mt-6 gl-p-3',
+          data: { testid: 'duo-enterprise-trial-alert' }
+        }
+      end
+
+      def icon
+        sprite_icon('tanuki-ai', css_class: 'gl-mr-2 !gl-align-baseline')
+      end
+
+      def title
+        s_('BillingPlans|Get the most out of GitLab with Ultimate and GitLab Duo Enterprise')
+      end
+
+      def primary_cta_options
+        {
+          href: primary_link,
+          variant: 'confirm',
+          button_text_classes: '!gl-whitespace-normal',
+          button_options: {
+            class: 'gl-w-full sm:gl-w-auto',
+            data: {
+              event_tracking: 'click_duo_enterprise_trial_billing_page',
+              event_label: primary_tracking_label
+            }
+          }
+        }
+      end
+
+      def primary_link
+        new_trial_path(namespace_id: namespace.id)
+      end
+
+      def primary_tracking_label
+        'ultimate_and_duo_enterprise_trial'
+      end
+
+      def primary_cta
+        s_('BillingPlans|Start free trial of GitLab Ultimate and GitLab Duo Enterprise')
+      end
+
+      def hand_raise_lead_data
+        {
+          glm_content: 'billing-group',
+          cta_tracking: {
+            action: 'hand_raise_form_viewed',
+            label: 'click_duo_enterprise_trial_billing_page'
+          }.to_json,
+          button_attributes: {
+            variant: 'confirm',
+            category: 'secondary',
+            class: 'gl-w-full sm:gl-w-auto'
+          }.to_json
+        }
+      end
+    end
+  end
+end
diff --git a/ee/app/components/gitlab_subscriptions/duo_enterprise_alert/free_component.rb b/ee/app/components/gitlab_subscriptions/duo_enterprise_alert/free_component.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e244e13a9e2b5597dbf10c5ff63f7a2561e5b5ba
--- /dev/null
+++ b/ee/app/components/gitlab_subscriptions/duo_enterprise_alert/free_component.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module GitlabSubscriptions
+  module DuoEnterpriseAlert
+    class FreeComponent < BaseComponent
+      private
+
+      def render?
+        duo_enterprise_trials_enabled? &&
+          namespace.free_plan? &&
+          GitlabSubscriptions::DuoEnterprise.no_add_on_purchase_for_namespace?(namespace)
+      end
+
+      def body
+        [
+          s_('BillingPlans|Start an Ultimate trial with GitLab Duo Enterprise to ' \
+            'try the complete set of features from GitLab. GitLab Duo Enterprise ' \
+            'gives you access to the full product offering from GitLab, including ' \
+            'AI-powered features. You can try it for free, no credit card required.')
+        ]
+      end
+    end
+  end
+end
diff --git a/ee/app/helpers/billing_plans_helper.rb b/ee/app/helpers/billing_plans_helper.rb
index 71708d33972c95bfc4f822004c1f167d0ee1433e..8ec9460e6fd0fe3b42df51820c8643b8b5fe5052 100644
--- a/ee/app/helpers/billing_plans_helper.rb
+++ b/ee/app/helpers/billing_plans_helper.rb
@@ -151,7 +151,7 @@ def add_namespace_plan_to_group_instructions
   def show_duo_enterprise_trial_alert?(namespace)
     return false if Feature.disabled?(:duo_enterprise_trials, current_user)
 
-    if namespace.ultimate_plan? || namespace.free_plan?
+    if namespace.ultimate_plan?
       GitlabSubscriptions::DuoEnterprise.no_add_on_purchase_for_namespace?(namespace)
     elsif namespace.premium_plan?
       GitlabSubscriptions::Duo.no_add_on_purchase_for_namespace?(namespace)
@@ -176,13 +176,6 @@ def duo_enterprise_trial_alert_data(namespace)
           s_('BillingPlans|Not ready to trial the full suite of GitLab and GitLab Duo features? Start a free trial of GitLab Duo Pro instead.')
         ]
       }
-    else
-      {
-        title: s_('BillingPlans|Get the most out of GitLab with Ultimate and GitLab Duo Enterprise'),
-        body: [
-          s_('BillingPlans|Start an Ultimate trial with GitLab Duo Enterprise to try the complete set of features from GitLab. GitLab Duo Enterprise gives you access to the full product offering from GitLab, including AI-powered features. You can try it for free, no credit card required.')
-        ]
-      }
     end
   end
 
diff --git a/ee/app/views/groups/billings/_free_and_trial_plan_billing_index.html.haml b/ee/app/views/groups/billings/_free_and_trial_plan_billing_index.html.haml
index d263a6e9d7c3dfe856bebcce6354ff0ac5f9c23c..8e0bb320b1f3ae73bb6e65688cf50c5c9706aaef 100644
--- a/ee/app/views/groups/billings/_free_and_trial_plan_billing_index.html.haml
+++ b/ee/app/views/groups/billings/_free_and_trial_plan_billing_index.html.haml
@@ -11,9 +11,8 @@
 
     = html_escape(s_("BillingPlans|Not the group you're looking for? %{all_groups_link}")) % { all_groups_link: all_groups_link.html_safe }
 
-  - if show_duo_enterprise_trial_alert?(namespace)
-    .billing-plan-divider.gl-mx-auto
-      = render 'shared/billings/duo_enterprise_trial_alert', namespace: namespace
+  .billing-plan-divider.gl-mx-auto
+    = render GitlabSubscriptions::DuoEnterpriseAlert::FreeComponent.new(namespace: namespace, user: current_user)
 
   .gl-flex-row.gl-flex.gl-flex-wrap.gl-justify-center.gl-mb-7.gl-ml-7{ data: { track_action: 'render', testid: 'billing-plans' } }
     = render Billing::PlanComponent.with_collection(plans_data, namespace: namespace, current_plan: current_plan)
diff --git a/ee/spec/components/gitlab_subscriptions/duo_enterprise_alert/free_component_spec.rb b/ee/spec/components/gitlab_subscriptions/duo_enterprise_alert/free_component_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c7ddbb3b9f472744090b80e7b154d87722163030
--- /dev/null
+++ b/ee/spec/components/gitlab_subscriptions/duo_enterprise_alert/free_component_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSubscriptions::DuoEnterpriseAlert::FreeComponent, :saas, :aggregate_failures,
+  type: :component, feature_category: :acquisition do
+  let(:namespace) { build(:group, id: non_existing_record_id) }
+  let(:user) { build(:user) }
+
+  subject(:component) do
+    render_inline(described_class.new(namespace: namespace, user: user)) && page
+  end
+
+  before do
+    build(:gitlab_subscription, :free, namespace: namespace)
+  end
+
+  context 'when duo_enterprise_trials is disabled' do
+    before do
+      stub_feature_flags(duo_enterprise_trials: false)
+    end
+
+    it { is_expected.to have_content('') }
+  end
+
+  context 'when ultimate_trial plan' do
+    before do
+      build(:gitlab_subscription, :ultimate_trial, :active_trial, namespace: namespace)
+    end
+
+    it { is_expected.to have_content('') }
+  end
+
+  context 'when there is Duo Enterprise add-on' do
+    before do
+      allow(GitlabSubscriptions::DuoEnterprise)
+        .to receive(:no_add_on_purchase_for_namespace?)
+        .with(namespace)
+        .and_return(false)
+    end
+
+    it { is_expected.to have_content('') }
+  end
+
+  context 'when rendering' do
+    it 'has the correct text' do
+      is_expected.to have_content(
+        'Get the most out of GitLab with Ultimate and GitLab Duo Enterprise'
+      )
+
+      is_expected.to have_content(
+        'Start an Ultimate trial with GitLab Duo Enterprise to try the ' \
+          'complete set of features from GitLab. GitLab Duo Enterprise gives ' \
+          'you access to the full product offering from GitLab, including ' \
+          'AI-powered features. You can try it for free, no credit card required.'
+      )
+    end
+
+    it 'has the primary action' do
+      is_expected.to have_link(
+        'Start free trial of GitLab Ultimate and GitLab Duo Enterprise',
+        href: new_trial_path(namespace_id: namespace.id)
+      )
+
+      is_expected.to have_css(
+        '[data-event-tracking="click_duo_enterprise_trial_billing_page"]' \
+          '[data-event-label="ultimate_and_duo_enterprise_trial"]'
+      )
+    end
+
+    it 'has the hand raise lead selector' do
+      is_expected.to have_selector('.js-hand-raise-lead-trigger')
+    end
+  end
+end
diff --git a/ee/spec/helpers/billing_plans_helper_spec.rb b/ee/spec/helpers/billing_plans_helper_spec.rb
index d9769ee813b7331d3b649fb4a785eee2c6174438..4fbdad5191f9305676db2105a374c8dfab31b455 100644
--- a/ee/spec/helpers/billing_plans_helper_spec.rb
+++ b/ee/spec/helpers/billing_plans_helper_spec.rb
@@ -600,16 +600,6 @@
       end
     end
 
-    context 'when free plan' do
-      before do
-        build(:gitlab_subscription, :free, namespace: namespace)
-      end
-
-      it_behaves_like 'available plan' do
-        let(:finder) { GitlabSubscriptions::DuoEnterprise }
-      end
-    end
-
     context 'when ultimate trial plan' do
       before do
         build(:gitlab_subscription, :ultimate_trial, :active_trial, namespace: namespace)
diff --git a/ee/spec/views/shared/billings/_duo_enterprise_trial_alert.html.haml_spec.rb b/ee/spec/views/shared/billings/_duo_enterprise_trial_alert.html.haml_spec.rb
index ede6949b68c7a3d7934e954c99f78566fde44d8b..0b98768478423259292f9760e605e8165294b196 100644
--- a/ee/spec/views/shared/billings/_duo_enterprise_trial_alert.html.haml_spec.rb
+++ b/ee/spec/views/shared/billings/_duo_enterprise_trial_alert.html.haml_spec.rb
@@ -103,45 +103,4 @@ def render
       )
     end
   end
-
-  context 'when free plan' do
-    before do
-      build(:gitlab_subscription, :free, namespace: group)
-    end
-
-    it 'contains the correct text' do
-      render
-
-      expect(rendered).to have_content(
-        'Get the most out of GitLab with Ultimate and GitLab Duo Enterprise'
-      )
-
-      expect(rendered).to have_content(
-        'Start an Ultimate trial with GitLab Duo Enterprise to try the ' \
-          'complete set of features from GitLab. GitLab Duo Enterprise gives ' \
-          'you access to the full product offering from GitLab, including ' \
-          'AI-powered features. You can try it for free, no credit card required.'
-      )
-    end
-
-    it 'contains the primary action' do
-      render
-
-      expect(rendered).to have_link(
-        'Start free trial of GitLab Ultimate and GitLab Duo Enterprise',
-        href: new_trial_path(namespace_id: group.id)
-      )
-
-      expect(rendered).to have_css(
-        '[data-event-tracking="click_duo_enterprise_trial_billing_page"]' \
-          '[data-event-label="ultimate_and_duo_enterprise_trial"]'
-      )
-    end
-
-    it 'contains the hand raise lead selector' do
-      render
-
-      expect(rendered).to have_selector('.js-hand-raise-lead-trigger')
-    end
-  end
 end