diff --git a/app/graphql/types/work_item_type.rb b/app/graphql/types/work_item_type.rb
index 56fa53355fd77f4f9c4832c6f568accecb976452..c19ece80cdff1a3c95c14503c111bc0016ff49a0 100644
--- a/app/graphql/types/work_item_type.rb
+++ b/app/graphql/types/work_item_type.rb
@@ -60,7 +60,19 @@ class WorkItemType < BaseObject
     field :widgets,
       [Types::WorkItems::WidgetInterface],
       null: true,
-      description: 'Collection of widgets that belong to the work item.'
+      description: 'Collection of widgets that belong to the work item.' do
+        argument :except_types, [::Types::WorkItems::WidgetTypeEnum],
+          required: false,
+          default_value: nil,
+          description: 'Except widgets of the given types.'
+        argument :only_types, [::Types::WorkItems::WidgetTypeEnum],
+          required: false,
+          default_value: nil,
+          description: 'Only widgets of the given types.'
+
+        validates mutually_exclusive: %i[except_types only_types]
+      end
+
     field :work_item_type, Types::WorkItems::TypeType, null: false,
       description: 'Type assigned to the work item.'
 
diff --git a/app/models/work_item.rb b/app/models/work_item.rb
index 4b1d3bc75d8775162f219739c164b4778118f991..4a5d6d56e4a400ebc30b858abd70aa1c30027342 100644
--- a/app/models/work_item.rb
+++ b/app/models/work_item.rb
@@ -146,10 +146,17 @@ def todoable_target_type_name
     %w[Issue WorkItem]
   end
 
-  def widgets
-    strong_memoize(:widgets) do
-      work_item_type.widgets(resource_parent).map do |widget_definition|
-        widget_definition.widget_class.new(self, widget_definition: widget_definition)
+  def widgets(except_types: [], only_types: nil)
+    raise ArgumentError, 'Only one filter is allowed' if only_types.present? && except_types.present?
+
+    strong_memoize_with(:widgets, only_types, except_types) do
+      except_types = Array.wrap(except_types)
+
+      widget_definitions.keys.filter_map do |type|
+        next if except_types.include?(type)
+        next if only_types&.exclude?(type)
+
+        get_widget(type)
       end
     end
   end
@@ -157,13 +164,21 @@ def widgets
   # Returns widget object if available
   # type parameter can be a symbol, for example, `:description`.
   def get_widget(type)
-    widgets.find do |widget|
-      widget.instance_of?(WorkItems::Widgets.const_get(type.to_s.camelize, false))
+    strong_memoize_with(type) do
+      break unless widget_definitions.key?(type.to_sym)
+
+      widget_definitions[type].build_widget(self)
     end
-  rescue NameError
-    nil
   end
 
+  def widget_definitions
+    work_item_type
+      .widgets(resource_parent)
+      .index_by(&:widget_type)
+      .symbolize_keys
+  end
+  strong_memoize_attr :widget_definitions
+
   def ancestors
     hierarchy.ancestors(hierarchy_order: :asc)
   end
diff --git a/app/models/work_items/widget_definition.rb b/app/models/work_items/widget_definition.rb
index fa2c602a3c7a6be713461b64ca95eca90024e049..a48afd23ce13deab9867ea95d1c21f65e87451e4 100644
--- a/app/models/work_items/widget_definition.rb
+++ b/app/models/work_items/widget_definition.rb
@@ -69,5 +69,9 @@ def widget_class
     rescue NameError
       nil
     end
+
+    def build_widget(work_item)
+      widget_class.new(work_item, widget_definition: self)
+    end
   end
 end
diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md
index 440387b58293bc424a08d717467da087635e5003..d6b0931382b711b47e714015535908a30d19337b 100644
--- a/doc/api/graphql/reference/_index.md
+++ b/doc/api/graphql/reference/_index.md
@@ -39458,7 +39458,6 @@ four standard [pagination arguments](#pagination-arguments):
 | <a id="workitemuserdiscussionscount"></a>`userDiscussionsCount` | [`Int!`](#int) | Number of user discussions in the work item. |
 | <a id="workitemuserpermissions"></a>`userPermissions` | [`WorkItemPermissions!`](#workitempermissions) | Permissions for the current user on the resource. |
 | <a id="workitemweburl"></a>`webUrl` | [`String`](#string) | URL of this object. |
-| <a id="workitemwidgets"></a>`widgets` | [`[WorkItemWidget!]`](#workitemwidget) | Collection of widgets that belong to the work item. |
 | <a id="workitemworkitemtype"></a>`workItemType` | [`WorkItemType!`](#workitemtype) | Type assigned to the work item. |
 
 #### Fields with arguments
@@ -39475,6 +39474,19 @@ Returns [`String!`](#string).
 | ---- | ---- | ----------- |
 | <a id="workitemreferencefull"></a>`full` | [`Boolean`](#boolean) | Boolean option specifying whether the reference should be returned in full. |
 
+##### `WorkItem.widgets`
+
+Collection of widgets that belong to the work item.
+
+Returns [`[WorkItemWidget!]`](#workitemwidget).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="workitemwidgetsexcepttypes"></a>`exceptTypes` | [`[WorkItemWidgetType!]`](#workitemwidgettype) | Except widgets of the given types. |
+| <a id="workitemwidgetsonlytypes"></a>`onlyTypes` | [`[WorkItemWidgetType!]`](#workitemwidgettype) | Only widgets of the given types. |
+
 ### `WorkItemClosingMergeRequest`
 
 #### Fields
diff --git a/spec/models/work_item_spec.rb b/spec/models/work_item_spec.rb
index 70b11f5c07cca219df141af26fc0c1237e65c33a..049aea5b5aa1a218f254bb404d96f54375a24453 100644
--- a/spec/models/work_item_spec.rb
+++ b/spec/models/work_item_spec.rb
@@ -187,16 +187,79 @@
   end
 
   describe '#widgets' do
-    subject { build(:work_item).widgets }
+    subject(:work_item) { build(:work_item) }
 
     it 'returns instances of supported widgets' do
-      is_expected.to include(
+      expect(work_item.widgets).to match_array([
+        instance_of(WorkItems::Widgets::Assignees),
+        instance_of(WorkItems::Widgets::AwardEmoji),
+        instance_of(WorkItems::Widgets::CrmContacts),
+        instance_of(WorkItems::Widgets::CurrentUserTodos),
         instance_of(WorkItems::Widgets::Description),
+        instance_of(WorkItems::Widgets::Designs),
+        instance_of(WorkItems::Widgets::Development),
+        instance_of(WorkItems::Widgets::EmailParticipants),
+        instance_of(WorkItems::Widgets::ErrorTracking),
         instance_of(WorkItems::Widgets::Hierarchy),
         instance_of(WorkItems::Widgets::Labels),
-        instance_of(WorkItems::Widgets::Assignees),
-        instance_of(WorkItems::Widgets::StartAndDueDate)
-      )
+        instance_of(WorkItems::Widgets::LinkedItems),
+        instance_of(WorkItems::Widgets::Milestone),
+        instance_of(WorkItems::Widgets::Notes),
+        instance_of(WorkItems::Widgets::Notifications),
+        instance_of(WorkItems::Widgets::Participants),
+        instance_of(WorkItems::Widgets::StartAndDueDate),
+        instance_of(WorkItems::Widgets::TimeTracking)
+      ])
+    end
+
+    context 'when filters are given' do
+      context 'when both only_types and except_types are given' do
+        it 'raises an error' do
+          expect { work_item.widgets(only_types: [true], except_types: [true]) }
+            .to raise_error(ArgumentError, 'Only one filter is allowed')
+        end
+      end
+
+      context 'when filtering by only_types' do
+        it 'only returns widgets on the given list' do
+          expect(work_item.widgets(only_types: [:milestone, :description])).to match_array([
+            instance_of(WorkItems::Widgets::Milestone),
+            instance_of(WorkItems::Widgets::Description)
+          ])
+        end
+      end
+
+      context 'when passing explicitly nil to except_types' do
+        it 'only returns widgets on the given list' do
+          expect(work_item.widgets(only_types: [:milestone, :description], except_types: nil)).to match_array([
+            instance_of(WorkItems::Widgets::Milestone),
+            instance_of(WorkItems::Widgets::Description)
+          ])
+        end
+      end
+
+      context 'when filtering by except_types' do
+        it 'only returns widgets on the given list' do
+          expect(work_item.widgets(except_types: [:milestone, :description])).to match_array([
+            instance_of(WorkItems::Widgets::Assignees),
+            instance_of(WorkItems::Widgets::AwardEmoji),
+            instance_of(WorkItems::Widgets::CrmContacts),
+            instance_of(WorkItems::Widgets::CurrentUserTodos),
+            instance_of(WorkItems::Widgets::Designs),
+            instance_of(WorkItems::Widgets::Development),
+            instance_of(WorkItems::Widgets::EmailParticipants),
+            instance_of(WorkItems::Widgets::ErrorTracking),
+            instance_of(WorkItems::Widgets::Hierarchy),
+            instance_of(WorkItems::Widgets::Labels),
+            instance_of(WorkItems::Widgets::LinkedItems),
+            instance_of(WorkItems::Widgets::Notes),
+            instance_of(WorkItems::Widgets::Notifications),
+            instance_of(WorkItems::Widgets::Participants),
+            instance_of(WorkItems::Widgets::StartAndDueDate),
+            instance_of(WorkItems::Widgets::TimeTracking)
+          ])
+        end
+      end
     end
   end
 
diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb
index 1600da2d2afb81e865680472d85086013dac2ead..473fe4d070716c2a689d4015f498d2c7f5209863 100644
--- a/spec/requests/api/graphql/work_item_spec.rb
+++ b/spec/requests/api/graphql/work_item_spec.rb
@@ -791,6 +791,64 @@ def pagination_results_data(nodes)
           )
         end
       end
+
+      context 'when filtering' do
+        context 'when selecting widgets' do
+          let(:work_item_fields) do
+            <<~GRAPHQL
+              id
+              widgets(onlyTypes: [DESCRIPTION]) {
+                type
+              }
+            GRAPHQL
+          end
+
+          it 'only returns selected widgets' do
+            expect(work_item_data).to include(
+              'id' => work_item.to_gid.to_s,
+              'widgets' => [{
+                'type' => 'DESCRIPTION'
+              }]
+            )
+          end
+        end
+
+        context 'when excluding widgets' do
+          let(:work_item_fields) do
+            <<~GRAPHQL
+              id
+              widgets(exceptTypes: [DESCRIPTION]) {
+                type
+              }
+            GRAPHQL
+          end
+
+          it 'does not return excluded widgets' do
+            expect(work_item_data).to include(
+              'id' => work_item.to_gid.to_s,
+              'widgets' => [
+                { "type" => "ASSIGNEES" },
+                { "type" => "AWARD_EMOJI" },
+                { "type" => "CRM_CONTACTS" },
+                { "type" => "CURRENT_USER_TODOS" },
+                { "type" => "DESIGNS" },
+                { "type" => "DEVELOPMENT" },
+                { "type" => "EMAIL_PARTICIPANTS" },
+                { "type" => "ERROR_TRACKING" },
+                { "type" => "HIERARCHY" },
+                { "type" => "LABELS" },
+                { "type" => "LINKED_ITEMS" },
+                { "type" => "MILESTONE" },
+                { "type" => "NOTES" },
+                { "type" => "NOTIFICATIONS" },
+                { "type" => "PARTICIPANTS" },
+                { "type" => "START_AND_DUE_DATE" },
+                { "type" => "TIME_TRACKING" }
+              ]
+            )
+          end
+        end
+      end
     end
 
     describe 'notes widget' do