diff --git a/core/lib/Drupal/Core/Datetime/Plugin/Field/FieldWidget/TimestampDatetimeWidget.php b/core/lib/Drupal/Core/Datetime/Plugin/Field/FieldWidget/TimestampDatetimeWidget.php
index 88efd5efe46ff501459ab871d58f90d13f1515c9..9fd92d571184b507ce87f0d827c41b3b1167c10c 100644
--- a/core/lib/Drupal/Core/Datetime/Plugin/Field/FieldWidget/TimestampDatetimeWidget.php
+++ b/core/lib/Drupal/Core/Datetime/Plugin/Field/FieldWidget/TimestampDatetimeWidget.php
@@ -3,22 +3,23 @@
 namespace Drupal\Core\Datetime\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Datetime\DrupalDateTime;
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'datetime timestamp' widget.
- *
- * @FieldWidget(
- *   id = "datetime_timestamp",
- *   label = @Translation("Datetime Timestamp"),
- *   field_types = {
- *     "timestamp",
- *     "created",
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'datetime_timestamp',
+  label: new TranslatableMarkup('Datetime Timestamp'),
+  field_types: [
+    'timestamp',
+    'created',
+  ],
+)]
 class TimestampDatetimeWidget extends WidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Attribute/FieldWidget.php b/core/lib/Drupal/Core/Field/Attribute/FieldWidget.php
new file mode 100644
index 0000000000000000000000000000000000000000..9b98af3cd5c0537ebcd298d1f2a8996d49f2d60b
--- /dev/null
+++ b/core/lib/Drupal/Core/Field/Attribute/FieldWidget.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Drupal\Core\Field\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines a FieldWidget attribute for plugin discovery.
+ *
+ * Plugin Namespace: Plugin\Field\FieldWidget
+ *
+ * Widgets handle how fields are displayed in edit forms.
+ *
+ * Additional attribute keys for widgets can be defined in
+ * hook_field_widget_info_alter().
+ *
+ * @see \Drupal\Core\Field\WidgetPluginManager
+ * @see \Drupal\Core\Field\WidgetInterface
+ *
+ * @ingroup field_widget
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class FieldWidget extends Plugin {
+
+  /**
+   * Constructs a FieldWidget attribute.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $label
+   *   (optional) The human-readable name of the widget type.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $description
+   *   (optional) A short description of the widget type.
+   * @param string[] $field_types
+   *   (optional) An array of field types the widget supports.
+   * @param bool $multiple_values
+   *   (optional) Does the field widget handles multiple values at once.
+   * @param int|null $weight
+   *   (optional) An integer to determine weight of this widget relative to
+   *   other widgets. Other widgets are in the Field UI when selecting a widget
+   *   for a given field.
+   * @param class-string|null $deriver
+   *   (optional) The deriver class.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly ?TranslatableMarkup $label = NULL,
+    public readonly ?TranslatableMarkup $description = NULL,
+    public readonly array $field_types = [],
+    public readonly bool $multiple_values = FALSE,
+    public readonly ?int $weight = NULL,
+    public readonly ?string $deriver = NULL,
+  ) {}
+
+}
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php
index a954dac07d2c9e0ccd8653f64e74ddcf15614a4a..b0f968124c41f90d153ac2cf91c9eaf56e63a5a4 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/BooleanCheckboxWidget.php
@@ -2,22 +2,21 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'boolean_checkbox' widget.
- *
- * @FieldWidget(
- *   id = "boolean_checkbox",
- *   label = @Translation("Single on/off checkbox"),
- *   field_types = {
- *     "boolean"
- *   },
- *   multiple_values = TRUE
- * )
  */
+#[FieldWidget(
+  id: 'boolean_checkbox',
+  label: new TranslatableMarkup('Single on/off checkbox'),
+  field_types: ['boolean'],
+  multiple_values: TRUE,
+)]
 class BooleanCheckboxWidget extends WidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
index bf7bb404200d7ce80873571348b9b8eb0be6c249..75c2b1097d43c14c4d92315b7807867a45496990 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EmailDefaultWidget.php
@@ -2,22 +2,21 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element\Email;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'email_default' widget.
- *
- * @FieldWidget(
- *   id = "email_default",
- *   label = @Translation("Email"),
- *   field_types = {
- *     "email"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'email_default',
+  label: new TranslatableMarkup('Email'),
+  field_types: ['email'],
+)]
 class EmailDefaultWidget extends WidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteTagsWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteTagsWidget.php
index 1feb4bb5e730a6b3158f409b6c4becac10a6069f..7515c69bb325b2ac7710c18252e7bb238ebf24fc 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteTagsWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteTagsWidget.php
@@ -2,22 +2,21 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'entity_reference_autocomplete_tags' widget.
- *
- * @FieldWidget(
- *   id = "entity_reference_autocomplete_tags",
- *   label = @Translation("Autocomplete (Tags style)"),
- *   description = @Translation("An autocomplete text field with tagging support."),
- *   field_types = {
- *     "entity_reference"
- *   },
- *   multiple_values = TRUE
- * )
  */
+#[FieldWidget(
+  id: 'entity_reference_autocomplete_tags',
+  label: new TranslatableMarkup('Autocomplete (Tags style)'),
+  description: new TranslatableMarkup('An autocomplete text field with tagging support.'),
+  field_types: ['entity_reference'],
+  multiple_values: TRUE,
+)]
 class EntityReferenceAutocompleteTagsWidget extends EntityReferenceAutocompleteWidget {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php
index 1677c400fe8add174eb1df880c974c26ab055072..f373ac800b828fe1c60d1daf1729b928c75abe5a 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php
@@ -2,24 +2,23 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\user\EntityOwnerInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
  * Plugin implementation of the 'entity_reference_autocomplete' widget.
- *
- * @FieldWidget(
- *   id = "entity_reference_autocomplete",
- *   label = @Translation("Autocomplete"),
- *   description = @Translation("An autocomplete text field."),
- *   field_types = {
- *     "entity_reference"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'entity_reference_autocomplete',
+  label: new TranslatableMarkup('Autocomplete'),
+  description: new TranslatableMarkup('An autocomplete text field.'),
+  field_types: ['entity_reference'],
+)]
 class EntityReferenceAutocompleteWidget extends WidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/LanguageSelectWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/LanguageSelectWidget.php
index 0872ba3b2078227462f75afd2e2814f02ff5f11f..a591aa085ecdb7234ecaa66091ba09ebc299ceaf 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/LanguageSelectWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/LanguageSelectWidget.php
@@ -2,22 +2,21 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'Language' widget.
- *
- * @FieldWidget(
- *   id = "language_select",
- *   label = @Translation("Language select"),
- *   field_types = {
- *     "language"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'language_select',
+  label: new TranslatableMarkup('Language select'),
+  field_types: ['language'],
+)]
 class LanguageSelectWidget extends WidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
index f3ad573408cd4df82de1f2021bc566040c49858d..e827bfd999e66c0572ea3dabbefa545784c375e9 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/NumberWidget.php
@@ -2,25 +2,26 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldFilteredMarkup;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
  * Plugin implementation of the 'number' widget.
- *
- * @FieldWidget(
- *   id = "number",
- *   label = @Translation("Number field"),
- *   field_types = {
- *     "integer",
- *     "decimal",
- *     "float"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'number',
+  label: new TranslatableMarkup('Number field'),
+  field_types: [
+    'integer',
+    'decimal',
+    'float',
+  ],
+)]
 class NumberWidget extends WidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsButtonsWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsButtonsWidget.php
index 5c9603ee5b5ecdbe3d2f617bcade4179289decc6..f348985553037b7ee41d615d4a06574b8e29cb6a 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsButtonsWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsButtonsWidget.php
@@ -2,25 +2,26 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'options_buttons' widget.
- *
- * @FieldWidget(
- *   id = "options_buttons",
- *   label = @Translation("Check boxes/radio buttons"),
- *   field_types = {
- *     "boolean",
- *     "entity_reference",
- *     "list_integer",
- *     "list_float",
- *     "list_string",
- *   },
- *   multiple_values = TRUE
- * )
  */
+#[FieldWidget(
+  id: 'options_buttons',
+  label: new TranslatableMarkup('Check boxes/radio buttons'),
+  field_types: [
+    'boolean',
+    'entity_reference',
+    'list_integer',
+    'list_float',
+    'list_string',
+  ],
+  multiple_values: TRUE,
+)]
 class OptionsButtonsWidget extends OptionsWidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsSelectWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsSelectWidget.php
index 33e92109d2532105c7935b226e8dbc7955c4a42b..c00aa2f875a08c507508d539199373a320d3f8a9 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsSelectWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/OptionsSelectWidget.php
@@ -3,24 +3,25 @@
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
 use Drupal\Component\Utility\Html;
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'options_select' widget.
- *
- * @FieldWidget(
- *   id = "options_select",
- *   label = @Translation("Select list"),
- *   field_types = {
- *     "entity_reference",
- *     "list_integer",
- *     "list_float",
- *     "list_string"
- *   },
- *   multiple_values = TRUE
- * )
  */
+#[FieldWidget(
+  id: 'options_select',
+  label: new TranslatableMarkup('Select list'),
+  field_types: [
+    'entity_reference',
+    'list_integer',
+    'list_float',
+    'list_string',
+  ],
+  multiple_values: TRUE,
+)]
 class OptionsSelectWidget extends OptionsWidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php
index 8ca174e4a6313c48526db5805dddf55764c496ea..cc550c2f03c77144d1be5ac639cb5a836352b176 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextareaWidget.php
@@ -2,21 +2,20 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'string_textarea' widget.
- *
- * @FieldWidget(
- *   id = "string_textarea",
- *   label = @Translation("Text area (multiple rows)"),
- *   field_types = {
- *     "string_long"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'string_textarea',
+  label: new TranslatableMarkup('Text area (multiple rows)'),
+  field_types: ['string_long'],
+)]
 class StringTextareaWidget extends WidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextfieldWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextfieldWidget.php
index 4d86a33f831f95e109ab4029b8dfd061a79ddfec..1523e4f618f72b2487657b94486b549b91f667df 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextfieldWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/StringTextfieldWidget.php
@@ -2,21 +2,20 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'string_textfield' widget.
- *
- * @FieldWidget(
- *   id = "string_textfield",
- *   label = @Translation("Textfield"),
- *   field_types = {
- *     "string"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'string_textfield',
+  label: new TranslatableMarkup('Textfield'),
+  field_types: ['string'],
+)]
 class StringTextfieldWidget extends WidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php
index 4d8dc0e14389ab0ac57bb6cd0d3a427a34125d7c..3052ca3039ac3dd0c72eb8b4b1d2864c2c79acdb 100644
--- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php
+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/UriWidget.php
@@ -2,21 +2,20 @@
 
 namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'uri' widget.
- *
- * @FieldWidget(
- *   id = "uri",
- *   label = @Translation("URI field"),
- *   field_types = {
- *     "uri",
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'uri',
+  label: new TranslatableMarkup('URI field'),
+  field_types: ['uri'],
+)]
 class UriWidget extends WidgetBase {
 
   /**
diff --git a/core/lib/Drupal/Core/Field/WidgetPluginManager.php b/core/lib/Drupal/Core/Field/WidgetPluginManager.php
index a2366f322706acf7f7fb288480d1773cbaa13873..501551887a33411f7ab46125fcbf5f928b33dadb 100644
--- a/core/lib/Drupal/Core/Field/WidgetPluginManager.php
+++ b/core/lib/Drupal/Core/Field/WidgetPluginManager.php
@@ -5,6 +5,7 @@
 use Drupal\Component\Plugin\Factory\DefaultFactory;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Plugin\DefaultPluginManager;
 
 /**
@@ -42,7 +43,7 @@ class WidgetPluginManager extends DefaultPluginManager {
    *   The 'field type' plugin manager.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, FieldTypePluginManagerInterface $field_type_manager) {
-    parent::__construct('Plugin/Field/FieldWidget', $namespaces, $module_handler, 'Drupal\Core\Field\WidgetInterface', 'Drupal\Core\Field\Annotation\FieldWidget');
+    parent::__construct('Plugin/Field/FieldWidget', $namespaces, $module_handler, 'Drupal\Core\Field\WidgetInterface', FieldWidget::class, 'Drupal\Core\Field\Annotation\FieldWidget');
 
     $this->setCacheBackend($cache_backend, 'field_widget_types_plugins');
     $this->alterInfo('field_widget_info');
diff --git a/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php b/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php
index 6e466e05b8b131e66986a0937f81d8d039148b83..bbafc4a7098e4364fb39c53e04f6448c266253a0 100644
--- a/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php
+++ b/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php
@@ -4,21 +4,20 @@
 
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Component\Utility\Html;
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Provides a default comment widget.
- *
- * @FieldWidget(
- *   id = "comment_default",
- *   label = @Translation("Comment"),
- *   field_types = {
- *     "comment"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'comment_default',
+  label: new TranslatableMarkup('Comment'),
+  field_types: ['comment'],
+)]
 class CommentWidget extends WidgetBase {
 
   /**
diff --git a/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php b/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php
index e641dbb8d5b6da14e75af1faaf68b5c3375ed8c5..4e8e77ff7da26310513460a05a49f4d44b2f0f72 100644
--- a/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php
+++ b/core/modules/content_moderation/src/Plugin/Field/FieldWidget/ModerationStateWidget.php
@@ -4,6 +4,7 @@
 
 use Drupal\content_moderation\Plugin\Field\ModerationStateFieldItemList;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsSelectWidget;
@@ -11,19 +12,17 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\content_moderation\ModerationInformation;
 use Drupal\content_moderation\StateTransitionValidationInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Plugin implementation of the 'moderation_state_default' widget.
- *
- * @FieldWidget(
- *   id = "moderation_state_default",
- *   label = @Translation("Moderation state"),
- *   field_types = {
- *     "string"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'moderation_state_default',
+  label: new TranslatableMarkup('Moderation state'),
+  field_types: ['string'],
+)]
 class ModerationStateWidget extends OptionsSelectWidget {
 
   /**
diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
index b61b032ed527a8fc4a551951e7b5014abdb00d0a..e7c27825595a139965ef11fad21fa8cdb7f65d95 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
@@ -2,20 +2,19 @@
 
 namespace Drupal\datetime\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'datetime_datelist' widget.
- *
- * @FieldWidget(
- *   id = "datetime_datelist",
- *   label = @Translation("Select list"),
- *   field_types = {
- *     "datetime"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'datetime_datelist',
+  label: new TranslatableMarkup('Select list'),
+  field_types: ['datetime'],
+)]
 class DateTimeDatelistWidget extends DateTimeWidgetBase {
 
   /**
diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
index f811fa9acc5c4311cc597b68d9bc1fda70657a18..9055d44982bfc1f1f5fe0e726d3bc017e7615fe4 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
@@ -3,23 +3,22 @@
 namespace Drupal\datetime\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Plugin implementation of the 'datetime_default' widget.
- *
- * @FieldWidget(
- *   id = "datetime_default",
- *   label = @Translation("Date and time"),
- *   field_types = {
- *     "datetime"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'datetime_default',
+  label: new TranslatableMarkup('Date and time'),
+  field_types: ['datetime'],
+)]
 class DateTimeDefaultWidget extends DateTimeWidgetBase {
 
   /**
diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php
index 4b8e56b5a9d1dabd758da4e31411f65eb2a455d2..0c90959607a9d04f3b7cd9e5b256e49291228493 100644
--- a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php
+++ b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php
@@ -2,21 +2,20 @@
 
 namespace Drupal\datetime_range\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\datetime_range\Plugin\Field\FieldType\DateRangeItem;
 
 /**
  * Plugin implementation of the 'daterange_datelist' widget.
- *
- * @FieldWidget(
- *   id = "daterange_datelist",
- *   label = @Translation("Select list"),
- *   field_types = {
- *     "daterange"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'daterange_datelist',
+  label: new TranslatableMarkup('Select list'),
+  field_types: ['daterange'],
+)]
 class DateRangeDatelistWidget extends DateRangeWidgetBase {
 
   /**
diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDefaultWidget.php b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDefaultWidget.php
index 2d1a85ac2ae239832bd2c5f534f3441488fad8b9..04c6f4eaf1c20d978fe9879eddb5c0b6027bce34 100644
--- a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDefaultWidget.php
+++ b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDefaultWidget.php
@@ -3,23 +3,22 @@
 namespace Drupal\datetime_range\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\datetime_range\Plugin\Field\FieldType\DateRangeItem;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Plugin implementation of the 'daterange_default' widget.
- *
- * @FieldWidget(
- *   id = "daterange_default",
- *   label = @Translation("Date and time range"),
- *   field_types = {
- *     "daterange"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'daterange_default',
+  label: new TranslatableMarkup('Date and time range'),
+  field_types: ['daterange'],
+)]
 class DateRangeDefaultWidget extends DateRangeWidgetBase {
 
   /**
diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index 84c15c590b35281af32dc036518cb1fe5a19cca7..7656b41d58b76c3175eb2c92ec6322740a50bc38 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -151,11 +151,11 @@ function hook_field_storage_config_update_forbid(\Drupal\field\FieldStorageConfi
  * which widget to use.
  *
  * Widgets are Plugins managed by the
- * \Drupal\Core\Field\WidgetPluginManager class. A widget is a plugin annotated
- * with class \Drupal\Core\Field\Annotation\FieldWidget that implements
- * \Drupal\Core\Field\WidgetInterface (in most cases, by
- * subclassing \Drupal\Core\Field\WidgetBase). Widget plugins need to be in the
- * namespace \Drupal\{your_module}\Plugin\Field\FieldWidget.
+ * \Drupal\Core\Field\WidgetPluginManager class. A widget is a plugin
+ * attributed with class \Drupal\Core\Field\Attribute\FieldWidget that
+ * implements \Drupal\Core\Field\WidgetInterface (in most cases, by subclassing
+ * \Drupal\Core\Field\WidgetBase). Widget plugins need to be in the namespace
+ * \Drupal\{your_module}\Plugin\Field\FieldWidget.
  *
  * Widgets are @link form_api Form API @endlink elements with additional
  * processing capabilities. The methods of the WidgetInterface object are
@@ -173,7 +173,7 @@ function hook_field_storage_config_update_forbid(\Drupal\field\FieldStorageConfi
  *
  * @param array $info
  *   An array of information on existing widget types, as collected by the
- *   annotation discovery mechanism.
+ *   plugin discovery mechanism.
  */
 function hook_field_widget_info_alter(array &$info) {
   // Let a new field type re-use an existing widget.
diff --git a/core/modules/field/tests/modules/field_plugins_test/src/Plugin/Field/FieldWidget/TestTextfieldWidget.php b/core/modules/field/tests/modules/field_plugins_test/src/Plugin/Field/FieldWidget/TestTextfieldWidget.php
index 3d1a57e3e0d0e3698d782315ffaf6fce148d59da..39a29c4b9954a4919b2a7fabde92a41c32574d7a 100644
--- a/core/modules/field/tests/modules/field_plugins_test/src/Plugin/Field/FieldWidget/TestTextfieldWidget.php
+++ b/core/modules/field/tests/modules/field_plugins_test/src/Plugin/Field/FieldWidget/TestTextfieldWidget.php
@@ -2,19 +2,20 @@
 
 namespace Drupal\field_plugins_test\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\text\Plugin\Field\FieldWidget\TextfieldWidget;
 
 /**
  * Plugin implementation of the 'field_plugins_test_text_widget' widget.
- *
- * @FieldWidget(
- *   id = "field_plugins_test_text_widget",
- *   label = @Translation("Test Text field"),
- *   field_types = {
- *     "text",
- *     "string"
- *   },
- * )
  */
+#[FieldWidget(
+  id: 'field_plugins_test_text_widget',
+  label: new TranslatableMarkup('Test Text field'),
+  field_types: [
+    'text',
+    'string',
+  ],
+)]
 class TestTextfieldWidget extends TextfieldWidget {
 }
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidget.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidget.php
index 7447623cbdc82d47dc28e80eafb0b2429023cc46..1e2bf60b83c470f848c9f12c6cf0d6f0bf2495b9 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidget.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidget.php
@@ -2,26 +2,27 @@
 
 namespace Drupal\field_test\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
  * Plugin implementation of the 'test_field_widget' widget.
- *
- * @FieldWidget(
- *   id = "test_field_widget",
- *   label = @Translation("Test widget"),
- *   field_types = {
- *     "field_test",
- *     "test_field",
- *     "hidden_test_field",
- *     "test_field_with_preconfigured_options"
- *   },
- *   weight = -10
- * )
  */
+#[FieldWidget(
+  id: 'test_field_widget',
+  label: new TranslatableMarkup('Test widget'),
+  field_types: [
+    'field_test',
+    'test_field',
+    'hidden_test_field',
+    'test_field_with_preconfigured_options',
+  ],
+  weight: -10,
+)]
 class TestFieldWidget extends WidgetBase {
 
   /**
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultilingual.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultilingual.php
index aabc74e6874e218801528accb87a3a5aef26c3da..5d94e51920e59c2f293494abbbbb36538be47fd4 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultilingual.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultilingual.php
@@ -2,20 +2,19 @@
 
 namespace Drupal\field_test\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'test_field_widget_multilingual' widget.
- *
- * @FieldWidget(
- *   id = "test_field_widget_multilingual",
- *   label = @Translation("Test widget - multilingual"),
- *   field_types = {
- *     "test_field",
- *   },
- * )
  */
+#[FieldWidget(
+  id: 'test_field_widget_multilingual',
+  label: new TranslatableMarkup('Test widget - multilingual'),
+  field_types: ['test_field'],
+)]
 class TestFieldWidgetMultilingual extends TestFieldWidget {
 
   /**
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php
index d4493bb55dcbafdd4addd11b447795df8c0b45eb..20e1f80b36ed23ab5bf92c25778754f826b61581 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultiple.php
@@ -2,10 +2,12 @@
 
 namespace Drupal\field_test\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
@@ -15,14 +17,13 @@
  * hook_field_widget_info_alter().
  *
  * @see field_test_field_widget_info_alter()
- *
- * @FieldWidget(
- *   id = "test_field_widget_multiple",
- *   label = @Translation("Test widget - multiple"),
- *   multiple_values = TRUE,
- *   weight = 10
- * )
  */
+#[FieldWidget(
+  id: 'test_field_widget_multiple',
+  label: new TranslatableMarkup('Test widget - multiple'),
+  multiple_values: TRUE,
+  weight: 10,
+)]
 class TestFieldWidgetMultiple extends WidgetBase {
 
   /**
diff --git a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultipleSingleValues.php b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultipleSingleValues.php
index 48b0ed0ba182b9dab9d5f94b445ac6fef29e35a1..2c715015908a87041a15a6c5ce2ae7c6a217f90c 100644
--- a/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultipleSingleValues.php
+++ b/core/modules/field/tests/modules/field_test/src/Plugin/Field/FieldWidget/TestFieldWidgetMultipleSingleValues.php
@@ -2,6 +2,9 @@
 
 namespace Drupal\field_test\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
 /**
  * Plugin implementation of the 'test_field_widget_multiple' widget.
  *
@@ -9,14 +12,13 @@
  * hook_field_widget_info_alter().
  *
  * @see field_test_field_widget_info_alter()
- *
- * @FieldWidget(
- *   id = "test_field_widget_multiple_single_value",
- *   label = @Translation("Test widget - multiple - single value"),
- *   multiple_values = FALSE,
- *   weight = 10
- * )
  */
+#[FieldWidget(
+  id: 'test_field_widget_multiple_single_value',
+  label: new TranslatableMarkup('Test widget - multiple - single value'),
+  multiple_values: FALSE,
+  weight: 10,
+)]
 class TestFieldWidgetMultipleSingleValues extends TestFieldWidgetMultiple {
 
 }
diff --git a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
index 458d4234bc5bf75e52ca8f05d8c6a9f8e3612e58..2edfae34c3339686c1979f261442b79fd9bf9128 100644
--- a/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
+++ b/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php
@@ -3,6 +3,7 @@
 namespace Drupal\file\Plugin\Field\FieldWidget;
 
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
@@ -18,15 +19,12 @@
 
 /**
  * Plugin implementation of the 'file_generic' widget.
- *
- * @FieldWidget(
- *   id = "file_generic",
- *   label = @Translation("File"),
- *   field_types = {
- *     "file"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'file_generic',
+  label: new TranslatableMarkup('File'),
+  field_types: ['file'],
+)]
 class FileWidget extends WidgetBase {
 
   /**
diff --git a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php
index 8f7505c33c15bf238146b760c157dd221afec64e..88cb0fcb94f49d60da68295d753b43e4fcecbbca 100644
--- a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php
+++ b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\image\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Image\ImageFactory;
@@ -14,15 +15,12 @@
 
 /**
  * Plugin implementation of the 'image_image' widget.
- *
- * @FieldWidget(
- *   id = "image_image",
- *   label = @Translation("Image"),
- *   field_types = {
- *     "image"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'image_image',
+  label: new TranslatableMarkup('Image'),
+  field_types: ['image'],
+)]
 class ImageWidget extends FileWidget {
 
   /**
diff --git a/core/modules/image/tests/modules/image_module_test/src/Plugin/Field/FieldWidget/DummyAjaxWidget.php b/core/modules/image/tests/modules/image_module_test/src/Plugin/Field/FieldWidget/DummyAjaxWidget.php
index 1d74a7615e280776a5f5e675ad8ac9200f1cdedd..2ab2b6b8296cc52fc5263ac43445c3361cef1e00 100644
--- a/core/modules/image/tests/modules/image_module_test/src/Plugin/Field/FieldWidget/DummyAjaxWidget.php
+++ b/core/modules/image/tests/modules/image_module_test/src/Plugin/Field/FieldWidget/DummyAjaxWidget.php
@@ -3,22 +3,21 @@
 namespace Drupal\image_module_test\Plugin\Field\FieldWidget;
 
 use Drupal\Core\Ajax\AjaxResponse;
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Default widget for Dummy AJAX test.
- *
- * @FieldWidget(
- *   id = "image_module_test_dummy_ajax_widget",
- *   label = @Translation("Dummy AJAX widget"),
- *   field_types = {
- *     "image_module_test_dummy_ajax"
- *   },
- *   multiple_values = TRUE,
- * )
  */
+#[FieldWidget(
+  id: 'image_module_test_dummy_ajax_widget',
+  label: new TranslatableMarkup('Dummy AJAX widget'),
+  field_types: ['image_module_test_dummy_ajax'],
+  multiple_values: TRUE,
+)]
 class DummyAjaxWidget extends WidgetBase {
 
   /**
diff --git a/core/modules/layout_builder/src/Plugin/Field/FieldWidget/LayoutBuilderWidget.php b/core/modules/layout_builder/src/Plugin/Field/FieldWidget/LayoutBuilderWidget.php
index 0195065ff5656dbe567f0f68fd0a2c1e9ea6003e..a6182a2832ec11ffc7e515a199e2f8a46b9d8224 100644
--- a/core/modules/layout_builder/src/Plugin/Field/FieldWidget/LayoutBuilderWidget.php
+++ b/core/modules/layout_builder/src/Plugin/Field/FieldWidget/LayoutBuilderWidget.php
@@ -2,26 +2,25 @@
 
 namespace Drupal\layout_builder\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * A widget to display the layout form.
  *
- * @FieldWidget(
- *   id = "layout_builder_widget",
- *   label = @Translation("Layout Builder Widget"),
- *   description = @Translation("A field widget for Layout Builder."),
- *   field_types = {
- *     "layout_section",
- *   },
- *   multiple_values = TRUE,
- * )
- *
  * @internal
  *   Plugin classes are internal.
  */
+#[FieldWidget(
+  id: 'layout_builder_widget',
+  label: new TranslatableMarkup('Layout Builder Widget'),
+  description: new TranslatableMarkup('A field widget for Layout Builder.'),
+  field_types: ['layout_section'],
+  multiple_values: TRUE,
+)]
 class LayoutBuilderWidget extends WidgetBase {
 
   /**
diff --git a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
index 97015d5bef8f5b80fbd2ef9c9eece71fb752abbd..80c5704f343b02682d3a46ab272643d4979f73ce 100644
--- a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
+++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\link\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 use Drupal\Core\Entity\Element\EntityAutocomplete;
@@ -14,15 +15,12 @@
 
 /**
  * Plugin implementation of the 'link' widget.
- *
- * @FieldWidget(
- *   id = "link_default",
- *   label = @Translation("Link"),
- *   field_types = {
- *     "link"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'link_default',
+  label: new TranslatableMarkup('Link'),
+  field_types: ['link'],
+)]
 class LinkWidget extends WidgetBase {
 
   /**
diff --git a/core/modules/media/src/Plugin/Field/FieldWidget/OEmbedWidget.php b/core/modules/media/src/Plugin/Field/FieldWidget/OEmbedWidget.php
index 9ca270c6a17b9e2b593a1a4bb9d4666ed446fb65..5fa53b2b9e924b3f839496b31c2c870f90eca64c 100644
--- a/core/modules/media/src/Plugin/Field/FieldWidget/OEmbedWidget.php
+++ b/core/modules/media/src/Plugin/Field/FieldWidget/OEmbedWidget.php
@@ -2,10 +2,12 @@
 
 namespace Drupal\media\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\Plugin\Field\FieldWidget\StringTextfieldWidget;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\media\Entity\MediaType;
 use Drupal\media\Plugin\media\Source\OEmbedInterface;
 
@@ -15,15 +17,12 @@
  * @internal
  *   This is an internal part of the oEmbed system and should only be used by
  *   oEmbed-related code in Drupal core.
- *
- * @FieldWidget(
- *   id = "oembed_textfield",
- *   label = @Translation("oEmbed URL"),
- *   field_types = {
- *     "string",
- *   },
- * )
  */
+#[FieldWidget(
+  id: 'oembed_textfield',
+  label: new TranslatableMarkup('oEmbed URL'),
+  field_types: ['string'],
+)]
 class OEmbedWidget extends StringTextfieldWidget {
 
   /**
diff --git a/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php
index 88c652890bea1f09b2e010dfb410939f593ee28a..14902898cd2d91c55fb29b05f5a25b096581076f 100644
--- a/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php
+++ b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Ajax\ReplaceCommand;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
@@ -31,19 +32,16 @@
 /**
  * Plugin implementation of the 'media_library_widget' widget.
  *
- * @FieldWidget(
- *   id = "media_library_widget",
- *   label = @Translation("Media library"),
- *   description = @Translation("Allows you to select items from the media library."),
- *   field_types = {
- *     "entity_reference"
- *   },
- *   multiple_values = TRUE,
- * )
- *
  * @internal
  *   Plugin classes are internal.
  */
+#[FieldWidget(
+  id: 'media_library_widget',
+  label: new TranslatableMarkup('Media library'),
+  description: new TranslatableMarkup('Allows you to select items from the media library.'),
+  field_types: ['entity_reference'],
+  multiple_values: TRUE,
+)]
 class MediaLibraryWidget extends WidgetBase implements TrustedCallbackInterface {
 
   /**
diff --git a/core/modules/media_library/tests/modules/media_library_test_widget/src/Plugin/Field/FieldWidget/MediaLibraryInceptionWidget.php b/core/modules/media_library/tests/modules/media_library_test_widget/src/Plugin/Field/FieldWidget/MediaLibraryInceptionWidget.php
index 8fe42c0c294082e68be760ceca8678cc22ec58f1..c4aedb7b4536adb2cd831d0655db449f428f9efb 100644
--- a/core/modules/media_library/tests/modules/media_library_test_widget/src/Plugin/Field/FieldWidget/MediaLibraryInceptionWidget.php
+++ b/core/modules/media_library/tests/modules/media_library_test_widget/src/Plugin/Field/FieldWidget/MediaLibraryInceptionWidget.php
@@ -2,9 +2,11 @@
 
 namespace Drupal\media_library_test_widget\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget;
 
 /**
@@ -13,17 +15,14 @@
  * This widget is used to simulate the media library widget nested inside
  * another widget that performs validation of required fields before there is
  * an opportunity to add media.
- *
- * @FieldWidget(
- *   id = "media_library_inception_widget",
- *   label = @Translation("Media library inception widget"),
- *   description = @Translation("Puts a widget in a widget for testing purposes."),
- *   field_types = {
- *     "entity_reference"
- *   },
- *   multiple_values = TRUE,
- * )
  */
+#[FieldWidget(
+  id: 'media_library_inception_widget',
+  label: new TranslatableMarkup('Media library inception widget'),
+  description: new TranslatableMarkup('Puts a widget in a widget for testing purposes.'),
+  field_types: ['entity_reference'],
+  multiple_values: TRUE,
+)]
 class MediaLibraryInceptionWidget extends MediaLibraryWidget {
 
   /**
diff --git a/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php b/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
index 088ef784e216bbca8fe433d416620449d8ff5dbd..837929520278c034117ba4bcc13c228b1a4a7fb4 100644
--- a/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
+++ b/core/modules/path/src/Plugin/Field/FieldWidget/PathWidget.php
@@ -2,22 +2,21 @@
 
 namespace Drupal\path\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
  * Plugin implementation of the 'path' widget.
- *
- * @FieldWidget(
- *   id = "path",
- *   label = @Translation("URL alias"),
- *   field_types = {
- *     "path"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'path',
+  label: new TranslatableMarkup('URL alias'),
+  field_types: ['path']
+)]
 class PathWidget extends WidgetBase {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldWidget/ShapeOnlyColorEditableWidget.php b/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldWidget/ShapeOnlyColorEditableWidget.php
index e12c6bff62ca4d7eb6857b647a8a115ff42d50c3..c962e514b98d8d085e04d2097cd52c7c49dd41e8 100644
--- a/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldWidget/ShapeOnlyColorEditableWidget.php
+++ b/core/modules/system/tests/modules/entity_test/src/Plugin/Field/FieldWidget/ShapeOnlyColorEditableWidget.php
@@ -2,21 +2,20 @@
 
 namespace Drupal\entity_test\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Plugin implementation of the 'shape_only_color_editable_widget' widget.
- *
- * @FieldWidget(
- *   id = "shape_only_color_editable_widget",
- *   label = @Translation("Shape widget with only color editable property"),
- *   field_types = {
- *     "shape"
- *   },
- * )
  */
+#[FieldWidget(
+  id: 'shape_only_color_editable_widget',
+  label: new TranslatableMarkup('Shape widget with only color editable property'),
+  field_types: ['shape'],
+)]
 class ShapeOnlyColorEditableWidget extends WidgetBase {
 
   /**
diff --git a/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php b/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
index 688929e9fdce91788644b4d1936ffda5bd83909a..a8dcdec775bd299e4f112fc7348adb14f88e7c96 100644
--- a/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
+++ b/core/modules/telephone/src/Plugin/Field/FieldWidget/TelephoneDefaultWidget.php
@@ -2,22 +2,21 @@
 
 namespace Drupal\telephone\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\telephone\Plugin\Field\FieldType\TelephoneItem;
 
 /**
  * Plugin implementation of the 'telephone_default' widget.
- *
- * @FieldWidget(
- *   id = "telephone_default",
- *   label = @Translation("Telephone number"),
- *   field_types = {
- *     "telephone"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'telephone_default',
+  label: new TranslatableMarkup('Telephone number'),
+  field_types: ['telephone'],
+)]
 class TelephoneDefaultWidget extends WidgetBase {
 
   /**
diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php
index 31af97846b7793dcca995a86b463c0e7545fe299..5dd7fff88a69604522307f7bfcf3c0d0d4d168b1 100644
--- a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php
+++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWidget.php
@@ -2,22 +2,21 @@
 
 namespace Drupal\text\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\Plugin\Field\FieldWidget\StringTextareaWidget;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
  * Plugin implementation of the 'text_textarea' widget.
- *
- * @FieldWidget(
- *   id = "text_textarea",
- *   label = @Translation("Text area (multiple rows)"),
- *   field_types = {
- *     "text_long"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'text_textarea',
+  label: new TranslatableMarkup('Text area (multiple rows)'),
+  field_types: ['text_long'],
+)]
 class TextareaWidget extends StringTextareaWidget {
 
   /**
diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php
index 3b1f541d7d73f2e78fab462ebfc289b6a9308bc5..96af85543ce18fdf7296a38a9f4aadd702013f6c 100644
--- a/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php
+++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextareaWithSummaryWidget.php
@@ -2,21 +2,20 @@
 
 namespace Drupal\text\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 
 /**
  * Plugin implementation of the 'text_textarea_with_summary' widget.
- *
- * @FieldWidget(
- *   id = "text_textarea_with_summary",
- *   label = @Translation("Text area with a summary"),
- *   field_types = {
- *     "text_with_summary"
- *   }
- * )
  */
+#[FieldWidget(
+  id: 'text_textarea_with_summary',
+  label: new TranslatableMarkup('Text area with a summary'),
+  field_types: ['text_with_summary'],
+)]
 class TextareaWithSummaryWidget extends TextareaWidget {
 
   /**
diff --git a/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php b/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php
index 8942ec338de3098750fc7e250fd041e4ff8a7f0b..16b7549681c17f68ff442dc461cec0f34bf41a29 100644
--- a/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php
+++ b/core/modules/text/src/Plugin/Field/FieldWidget/TextfieldWidget.php
@@ -2,22 +2,21 @@
 
 namespace Drupal\text\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Field\Attribute\FieldWidget;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\Plugin\Field\FieldWidget\StringTextfieldWidget;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 
 /**
  * Plugin implementation of the 'text_textfield' widget.
- *
- * @FieldWidget(
- *   id = "text_textfield",
- *   label = @Translation("Text field"),
- *   field_types = {
- *     "text"
- *   },
- * )
  */
+#[FieldWidget(
+  id: 'text_textfield',
+  label: new TranslatableMarkup('Text field'),
+  field_types: ['text'],
+)]
 class TextfieldWidget extends StringTextfieldWidget {
 
   /**