diff --git a/src/Attribute/EntityBrowserDisplay.php b/src/Attribute/EntityBrowserDisplay.php
new file mode 100644
index 0000000000000000000000000000000000000000..e96b7fe6c70c69d57c1ab3babbe1fc54841b22cb
--- /dev/null
+++ b/src/Attribute/EntityBrowserDisplay.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Drupal\entity_browser\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines an entity browser display attribute object.
+ *
+ * @see hook_entity_browser_display_info_alter()
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class EntityBrowserDisplay extends Plugin {
+  /**
+   * Constructs a new EntityBrowserDisplay instance.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup $label
+   *   The human-readable name of the display.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $description
+   *   (optional) A brief description of the display. This will be shown when
+   *   adding or configuring this display.
+   * @param bool $uses_route
+   *   Indicates that display uses route.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly TranslatableMarkup $label,
+    public readonly ?TranslatableMarkup $description = NULL,
+    public bool $uses_route = FALSE,
+    public ?string $provider = NULL,
+  ) {}
+}
diff --git a/src/Attribute/EntityBrowserFieldWidgetDisplay.php b/src/Attribute/EntityBrowserFieldWidgetDisplay.php
new file mode 100644
index 0000000000000000000000000000000000000000..312b5bbecd119b9f13cdc649bd1e7c2bdb2e33f1
--- /dev/null
+++ b/src/Attribute/EntityBrowserFieldWidgetDisplay.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\entity_browser\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines an entity browser field widget display attribute object.
+ *
+ * @see hook_entity_browser_field_widget_display_info_alter()
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class EntityBrowserFieldWidgetDisplay extends Plugin {
+
+  /**
+   * Constructs a new SensorPlugin instance.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup $label
+   *   The human-readable name of the field widget display.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $description
+   *   (optional) A brief description of the field widget display. This will be
+   *   shown when adding or configuring this display.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly TranslatableMarkup $label,
+    public readonly ?TranslatableMarkup $description = NULL,
+    public ?string $provider = NULL,
+  ) {}
+
+}
diff --git a/src/Attribute/EntityBrowserSelectionDisplay.php b/src/Attribute/EntityBrowserSelectionDisplay.php
new file mode 100644
index 0000000000000000000000000000000000000000..417956c38499c0e0d0e6d30b33aa2eb969855772
--- /dev/null
+++ b/src/Attribute/EntityBrowserSelectionDisplay.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Drupal\entity_browser\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines an entity browser selection display attribute object.
+ *
+ * @see hook_entity_browser_selection_display_info_alter()
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class EntityBrowserSelectionDisplay extends Plugin {
+
+  /**
+   * Constructs a new SensorPlugin instance.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup $label
+   *   The human-readable name of the selection display.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $description
+   *   A brief description of the selection display. This will be shown when
+   *   adding or configuring this selection display.
+   * @param bool $acceptPreselection
+   *   Preselection support. This will be used by entity browser form element to
+   *   check, if selection display accepts preselection of entities.
+   * @param bool $js_commands
+   *   Indicates that javascript commands can be executed for Selection display.
+   *   Currently supported javascript commands are adding and removing selection
+   *   from selection display. Javascript commands use Ajax requests to load
+   *   relevant changes and makes user experience way better, because form is
+   *   not flashed every time.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly TranslatableMarkup $label,
+    public readonly ?TranslatableMarkup $description = NULL,
+    public readonly bool $acceptPreselection = FALSE,
+    public readonly bool $js_commands = FALSE,
+    public ?string $provider = NULL,
+  ) {}
+
+}
diff --git a/src/Attribute/EntityBrowserWidget.php b/src/Attribute/EntityBrowserWidget.php
new file mode 100644
index 0000000000000000000000000000000000000000..e06a926bb1ed03cf46cf98ab165628096702d4b2
--- /dev/null
+++ b/src/Attribute/EntityBrowserWidget.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\entity_browser\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines an entity browser widget annotation object.
+ *
+ * @see hook_entity_browser_widget_info_alter()
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class EntityBrowserWidget extends Plugin {
+  /**
+   * Constructs a new SensorPlugin instance.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup $label
+   *   The human-readable name of the widget.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $description
+   *   (optional) A brief description of the widget. This will be shown when
+   *   adding or configuring this widget.
+   * @param bool $auto_select
+   *   Indicates that widget supports auto selection of entities.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly TranslatableMarkup $label,
+    public readonly ?TranslatableMarkup $description = NULL,
+    public readonly bool $auto_select = FALSE,
+    public ?string $provider = NULL,
+  ) {}
+
+}
diff --git a/src/Attribute/EntityBrowserWidgetSelector.php b/src/Attribute/EntityBrowserWidgetSelector.php
new file mode 100644
index 0000000000000000000000000000000000000000..ec20b710869e7d88c22f77f9b0af01718558bc50
--- /dev/null
+++ b/src/Attribute/EntityBrowserWidgetSelector.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\entity_browser\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines an entity browser widget selector attribute object.
+ *
+ * @see hook_entity_browser_widget_selector_info_alter()
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class EntityBrowserWidgetSelector extends Plugin {
+  /**
+   * Constructs a new SensorPlugin instance.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup $label
+   *   The human-readable name of the widget selector.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $description
+   *   (optional) A brief description of the widget selector. This will be shown
+   *   when adding or configuring this widget selector.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly TranslatableMarkup $label,
+    public readonly ?TranslatableMarkup $description = NULL,
+    public ?string $provider = NULL,
+  ) {}
+
+}
diff --git a/src/Attribute/EntityBrowserWidgetValidation.php b/src/Attribute/EntityBrowserWidgetValidation.php
new file mode 100644
index 0000000000000000000000000000000000000000..ac35e16e4de34706a258c9890affa7b92d6796ad
--- /dev/null
+++ b/src/Attribute/EntityBrowserWidgetValidation.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\entity_browser\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines an entity browser widget validation attribute object.
+ *
+ * @see hook_entity_browser_widget_validation_info_alter()
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class EntityBrowserWidgetValidation extends Plugin {
+
+  /**
+   * Constructs a new SensorPlugin instance.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup $label
+   *   The human-readable name of the widget validator.
+   * @param string|null $data_type
+   *   (optional) The data type plugin ID, for which a constraint should be
+   *   added.
+   * @param string|null $constraint
+   *   (optional) The constraint ID.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly TranslatableMarkup $label,
+    public readonly ?string $data_type = NULL,
+    public readonly ?string $constraint = NULL,
+    public ?string $provider = NULL,
+  ) {}
+
+}
diff --git a/src/DisplayManager.php b/src/DisplayManager.php
index 44a01389e95617b1d23bffce7f3fd4d24aed507f..e3f1a9c4aaa92951e0fcebf82490e55664e2db9e 100644
--- a/src/DisplayManager.php
+++ b/src/DisplayManager.php
@@ -23,7 +23,7 @@ class DisplayManager extends DefaultPluginManager {
    *   The module handler.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/EntityBrowser/Display', $namespaces, $module_handler, 'Drupal\entity_browser\DisplayInterface', 'Drupal\entity_browser\Annotation\EntityBrowserDisplay');
+    parent::__construct('Plugin/EntityBrowser/Display', $namespaces, $module_handler, 'Drupal\entity_browser\DisplayInterface', 'Drupal\entity_browser\Attribute\EntityBrowserDisplay', 'Drupal\entity_browser\Annotation\EntityBrowserDisplay');
 
     $this->alterInfo('entity_browser_display_info');
     $this->setCacheBackend($cache_backend, 'entity_browser_display_plugins');
diff --git a/src/FieldWidgetDisplayManager.php b/src/FieldWidgetDisplayManager.php
index 90b6f4a4866bd88ac95b7c035465d244f239707b..70cb9a3e77a778aac3834ff3fc6980ac267ecfe4 100644
--- a/src/FieldWidgetDisplayManager.php
+++ b/src/FieldWidgetDisplayManager.php
@@ -23,7 +23,7 @@ class FieldWidgetDisplayManager extends DefaultPluginManager {
    *   The module handler.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/EntityBrowser/FieldWidgetDisplay', $namespaces, $module_handler, 'Drupal\entity_browser\FieldWidgetDisplayInterface', 'Drupal\entity_browser\Annotation\EntityBrowserFieldWidgetDisplay');
+    parent::__construct('Plugin/EntityBrowser/FieldWidgetDisplay', $namespaces, $module_handler, 'Drupal\entity_browser\FieldWidgetDisplayInterface', 'Drupal\entity_browser\Attribute\EntityBrowserFieldWidgetDisplay', 'Drupal\entity_browser\Annotation\EntityBrowserFieldWidgetDisplay');
 
     $this->alterInfo('entity_browser_field_widget_display_info');
     $this->setCacheBackend($cache_backend, 'entity_browser_field_widget_display_plugins');
diff --git a/src/Plugin/EntityBrowser/Display/IFrame.php b/src/Plugin/EntityBrowser/Display/IFrame.php
index 4f0252f42fd180f5dfb93f8d920a7ed14f4b9d14..74094f4e01d44d31413110101f91c22a22cc1b2d 100644
--- a/src/Plugin/EntityBrowser/Display/IFrame.php
+++ b/src/Plugin/EntityBrowser/Display/IFrame.php
@@ -4,7 +4,9 @@ namespace Drupal\entity_browser\Plugin\EntityBrowser\Display;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
+use Drupal\entity_browser\Attribute\EntityBrowserDisplay;
 use Drupal\entity_browser\DisplayBase;
 use Drupal\entity_browser\DisplayRouterInterface;
 use Drupal\entity_browser\Events\AlterEntityBrowserDisplayData;
@@ -15,14 +17,13 @@ use Symfony\Component\HttpKernel\Event\ResponseEvent;
 
 /**
  * Presents entity browser in an iFrame.
- *
- * @EntityBrowserDisplay(
- *   id = "iframe",
- *   label = @Translation("iFrame"),
- *   description = @Translation("Displays the entity browser in an iFrame container embedded into the main page."),
- *   uses_route = TRUE
- * )
  */
+#[EntityBrowserDisplay(
+  id: 'iframe',
+  label: new TranslatableMarkup('iFrame'),
+  description: new TranslatableMarkup('Displays the entity browser in an iFrame container embedded into the main page.'),
+  uses_route: TRUE
+)]
 class IFrame extends DisplayBase implements DisplayRouterInterface {
 
   /**
diff --git a/src/Plugin/EntityBrowser/Display/Modal.php b/src/Plugin/EntityBrowser/Display/Modal.php
index 9070886005592ce8ce96869640b790f935086a86..45191c288e2246a5477c219ba18fb36bcd10b5bf 100644
--- a/src/Plugin/EntityBrowser/Display/Modal.php
+++ b/src/Plugin/EntityBrowser/Display/Modal.php
@@ -5,7 +5,9 @@ namespace Drupal\entity_browser\Plugin\EntityBrowser\Display;
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Ajax\OpenDialogCommand;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
+use Drupal\entity_browser\Attribute\EntityBrowserDisplay;
 use Drupal\entity_browser\DisplayBase;
 use Drupal\entity_browser\Events\Events;
 use Drupal\entity_browser\Events\RegisterJSCallbacks;
@@ -14,15 +16,14 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\entity_browser\Events\AlterEntityBrowserDisplayData;
 
 /**
- * Presents entity browser in an Modal.
- *
- * @EntityBrowserDisplay(
- *   id = "modal",
- *   label = @Translation("Modal"),
- *   description = @Translation("Displays the entity browser in a modal window."),
- *   uses_route = TRUE
- * )
+ * Presents entity browser in a Modal.
  */
+#[EntityBrowserDisplay(
+  id: 'modal',
+  label: new TranslatableMarkup('Modal'),
+  description: new TranslatableMarkup('Displays the entity browser in a modal window.'),
+  uses_route: TRUE
+)]
 class Modal extends IFrame {
 
   /**
diff --git a/src/Plugin/EntityBrowser/Display/Standalone.php b/src/Plugin/EntityBrowser/Display/Standalone.php
index 47a5ab299c27e9aa7757cf4d21f24281543dae89..461b159e49c04283fab2446d787dc934cbc9f4fa 100644
--- a/src/Plugin/EntityBrowser/Display/Standalone.php
+++ b/src/Plugin/EntityBrowser/Display/Standalone.php
@@ -2,20 +2,21 @@
 
 namespace Drupal\entity_browser\Plugin\EntityBrowser\Display;
 
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserDisplay;
 use Drupal\entity_browser\DisplayBase;
 use Drupal\entity_browser\DisplayRouterInterface;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Presents entity browser as a standalone form.
- *
- * @EntityBrowserDisplay(
- *   id = "standalone",
- *   label = @Translation("Standalone form"),
- *   description = @Translation("Displays the entity browser as a standalone form. Only intended for testing or very specific use cases."),
- *   uses_route = TRUE
- * )
  */
+#[EntityBrowserDisplay(
+  id: 'standalone',
+  label: new TranslatableMarkup('Standalone form'),
+  description: new TranslatableMarkup('Displays the entity browser as a standalone form. Only intended for testing or very specific use cases.'),
+  uses_route: TRUE
+)]
 class Standalone extends DisplayBase implements DisplayRouterInterface {
 
   /**
diff --git a/src/Plugin/EntityBrowser/FieldWidgetDisplay/EntityLabel.php b/src/Plugin/EntityBrowser/FieldWidgetDisplay/EntityLabel.php
index bfd24d810b8b9f9df7a66cd4134c7e520ed34495..e0c1f7b651117b5aeee36c959980334aa4a2680b 100644
--- a/src/Plugin/EntityBrowser/FieldWidgetDisplay/EntityLabel.php
+++ b/src/Plugin/EntityBrowser/FieldWidgetDisplay/EntityLabel.php
@@ -6,18 +6,20 @@ use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserDisplay;
+use Drupal\entity_browser\Attribute\EntityBrowserFieldWidgetDisplay;
 use Drupal\entity_browser\FieldWidgetDisplayBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Displays a label of the entity.
- *
- * @EntityBrowserFieldWidgetDisplay(
- *   id = "label",
- *   label = @Translation("Entity label"),
- *   description = @Translation("Displays entity with a label.")
- * )
  */
+#[EntityBrowserFieldWidgetDisplay(
+  id: 'label',
+  label: new TranslatableMarkup('Entity label'),
+  description: new TranslatableMarkup('Displays entity with a label.'),
+)]
 class EntityLabel extends FieldWidgetDisplayBase implements ContainerFactoryPluginInterface {
 
   /**
diff --git a/src/Plugin/EntityBrowser/FieldWidgetDisplay/ImageThumbnail.php b/src/Plugin/EntityBrowser/FieldWidgetDisplay/ImageThumbnail.php
index 3b371b62a117271fb04d8f470421acec4e28fc4b..391e0117484ffd270b7233d9efb4426717c64dfd 100644
--- a/src/Plugin/EntityBrowser/FieldWidgetDisplay/ImageThumbnail.php
+++ b/src/Plugin/EntityBrowser/FieldWidgetDisplay/ImageThumbnail.php
@@ -7,19 +7,20 @@ use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserFieldWidgetDisplay;
 use Drupal\entity_browser\FieldWidgetDisplayBase;
 use Drupal\file\FileInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Displays image thumbnail.
- *
- * @EntityBrowserFieldWidgetDisplay(
- *   id = "thumbnail",
- *   label = @Translation("Image thumbnail"),
- *   description = @Translation("Displays image files as thumbnails")
- * )
  */
+#[EntityBrowserFieldWidgetDisplay(
+  id: 'thumbnail',
+  label: new TranslatableMarkup('Image thumbnail'),
+  description: new TranslatableMarkup('Displays image files as thumbnails'),
+)]
 class ImageThumbnail extends FieldWidgetDisplayBase implements ContainerFactoryPluginInterface {
 
   /**
diff --git a/src/Plugin/EntityBrowser/FieldWidgetDisplay/RenderedEntity.php b/src/Plugin/EntityBrowser/FieldWidgetDisplay/RenderedEntity.php
index 3c900c5c62026666de2df95dcfbab0a358f4dd7b..f34d16958d457fe5669d116e358877026452c8e7 100644
--- a/src/Plugin/EntityBrowser/FieldWidgetDisplay/RenderedEntity.php
+++ b/src/Plugin/EntityBrowser/FieldWidgetDisplay/RenderedEntity.php
@@ -6,18 +6,19 @@ use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserFieldWidgetDisplay;
 use Drupal\entity_browser\FieldWidgetDisplayBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Displays the fully rendered entity.
- *
- * @EntityBrowserFieldWidgetDisplay(
- *   id = "rendered_entity",
- *   label = @Translation("Rendered entity"),
- *   description = @Translation("Displays fully rendered entity.")
- * )
  */
+#[EntityBrowserFieldWidgetDisplay(
+  id: 'rendered_entity',
+  label: new TranslatableMarkup('Rendered entity'),
+  description: new TranslatableMarkup('Displays image files as thumbnails'),
+)]
 class RenderedEntity extends FieldWidgetDisplayBase implements ContainerFactoryPluginInterface {
 
   /**
diff --git a/src/Plugin/EntityBrowser/SelectionDisplay/MultiStepDisplay.php b/src/Plugin/EntityBrowser/SelectionDisplay/MultiStepDisplay.php
index 7178ce56cd9fc63ad8930904fb03427f03d1da83..1144c190350a2afe39c16e57bd50cce3f2b581f4 100644
--- a/src/Plugin/EntityBrowser/SelectionDisplay/MultiStepDisplay.php
+++ b/src/Plugin/EntityBrowser/SelectionDisplay/MultiStepDisplay.php
@@ -7,20 +7,21 @@ use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\InvokeCommand;
 use Drupal\Core\Ajax\ReplaceCommand;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserSelectionDisplay;
 use Drupal\entity_browser\SelectionDisplayBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Show current selection and delivers selected entities.
- *
- * @EntityBrowserSelectionDisplay(
- *   id = "multi_step_display",
- *   label = @Translation("Multi step selection display"),
- *   description = @Translation("Shows the current selection display, allowing to mix elements selected through different widgets in several steps."),
- *   acceptPreselection = TRUE,
- *   js_commands = TRUE
- * )
  */
+#[EntityBrowserSelectionDisplay(
+  id: 'multi_step_display',
+  label: new TranslatableMarkup('Multi step selection display'),
+  description: new TranslatableMarkup('Shows the current selection display, allowing to mix elements selected through different widgets in several steps.'),
+  acceptPreselection: TRUE,
+  js_commands: TRUE,
+)]
 class MultiStepDisplay extends SelectionDisplayBase {
 
   /**
diff --git a/src/Plugin/EntityBrowser/SelectionDisplay/NoDisplay.php b/src/Plugin/EntityBrowser/SelectionDisplay/NoDisplay.php
index 8e9d18463005b11e756f70c34964984bbd83282c..8afee86bfb854eab75a1e51b42b1028a812f3bb5 100644
--- a/src/Plugin/EntityBrowser/SelectionDisplay/NoDisplay.php
+++ b/src/Plugin/EntityBrowser/SelectionDisplay/NoDisplay.php
@@ -3,19 +3,20 @@
 namespace Drupal\entity_browser\Plugin\EntityBrowser\SelectionDisplay;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserSelectionDisplay;
 use Drupal\entity_browser\SelectionDisplayBase;
 
 /**
  * Does not show current selection and immediately delivers selected entities.
- *
- * @EntityBrowserSelectionDisplay(
- *   id = "no_display",
- *   label = @Translation("No selection display"),
- *   description = @Translation("Skips the current selection display and immediately delivers the entities selected."),
- *   acceptPreselection = FALSE,
- *   js_commands = FALSE
- * )
  */
+#[EntityBrowserSelectionDisplay(
+  id: 'no_display',
+  label: new TranslatableMarkup('No selection display'),
+  description: new TranslatableMarkup('Skips the current selection display and immediately delivers the entities selected.'),
+  acceptPreselection: FALSE,
+  js_commands: FALSE,
+)]
 class NoDisplay extends SelectionDisplayBase {
 
   /**
diff --git a/src/Plugin/EntityBrowser/SelectionDisplay/View.php b/src/Plugin/EntityBrowser/SelectionDisplay/View.php
index 1542d7f31c9174d428bc27c63478c6bb6e837339..d0440b1474fb554c7611155ed347906f4bc7b038 100644
--- a/src/Plugin/EntityBrowser/SelectionDisplay/View.php
+++ b/src/Plugin/EntityBrowser/SelectionDisplay/View.php
@@ -4,22 +4,23 @@ namespace Drupal\entity_browser\Plugin\EntityBrowser\SelectionDisplay;
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserSelectionDisplay;
 use Drupal\entity_browser\SelectionDisplayBase;
 use Drupal\views\Views;
 use Drupal\views\Entity\View as ViewEntity;
 
 /**
  * Displays current selection in a View.
- *
- * @EntityBrowserSelectionDisplay(
- *   id = "view",
- *   label = @Translation("View selection display"),
- *   description = @Translation("Use a pre-configured view as selection area."),
- *   acceptPreselection = TRUE,
- *   provider = "views",
- *   js_commands = FALSE
- * )
  */
+#[EntityBrowserSelectionDisplay(
+  id: 'view',
+  label: new TranslatableMarkup('View selection display'),
+  description: new TranslatableMarkup('Use a pre-configured view as selection area.'),
+  acceptPreselection: TRUE,
+  js_commands: FALSE,
+  provider: 'views',
+)]
 class View extends SelectionDisplayBase {
 
   /**
@@ -113,7 +114,7 @@ class View extends SelectionDisplayBase {
     $values = $form_state->getValues();
 
     if (!empty($values['view'])) {
-      list($view_id, $display_id) = explode('.', $values['view']);
+      [$view_id, $display_id] = explode('.', $values['view']);
       $this->configuration['view'] = $view_id;
       $this->configuration['view_display'] = $display_id;
     }
diff --git a/src/Plugin/EntityBrowser/Widget/MediaImageUpload.php b/src/Plugin/EntityBrowser/Widget/MediaImageUpload.php
index 34c538354d480887890f828bc010639f11798567..40ac88f177edfc89d5cdcb485e1234d5c106d42a 100644
--- a/src/Plugin/EntityBrowser/Widget/MediaImageUpload.php
+++ b/src/Plugin/EntityBrowser/Widget/MediaImageUpload.php
@@ -3,20 +3,21 @@
 namespace Drupal\entity_browser\Plugin\EntityBrowser\Widget;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
+use Drupal\entity_browser\Attribute\EntityBrowserWidget;
 use Drupal\entity_browser\Plugin\EntityBrowser\Widget\Upload as FileUpload;
 use Drupal\media\MediaInterface;
 
 /**
  * Uses upload to create media images.
- *
- * @EntityBrowserWidget(
- *   id = "media_image_upload",
- *   label = @Translation("Upload images as media items"),
- *   description = @Translation("Upload widget that will create media entities of the uploaded images."),
- *   auto_select = FALSE
- * )
  */
+#[EntityBrowserWidget(
+  id: 'media_image_upload',
+  label: new TranslatableMarkup('Upload images as media items'),
+  description: new TranslatableMarkup('Upload widget that will create media entities of the uploaded images.'),
+  auto_select: FALSE
+)]
 class MediaImageUpload extends FileUpload {
 
   /**
diff --git a/src/Plugin/EntityBrowser/Widget/Upload.php b/src/Plugin/EntityBrowser/Widget/Upload.php
index 065b2eaaf059c802991be98975edd6abb7f4d477..95912a0218516dbfc53d767bfd097417cd143a06 100644
--- a/src/Plugin/EntityBrowser/Widget/Upload.php
+++ b/src/Plugin/EntityBrowser/Widget/Upload.php
@@ -4,20 +4,21 @@ namespace Drupal\entity_browser\Plugin\EntityBrowser\Widget;
 
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserWidget;
 use Drupal\entity_browser\WidgetBase;
 use Drupal\file\FileInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Adds an upload field browser's widget.
- *
- * @EntityBrowserWidget(
- *   id = "upload",
- *   label = @Translation("Upload"),
- *   description = @Translation("Adds an upload field browser's widget."),
- *   auto_select = FALSE
- * )
  */
+#[EntityBrowserWidget(
+  id: 'upload',
+  label: new TranslatableMarkup('Upload'),
+  description: new TranslatableMarkup("Adds an upload field browser's widget."),
+  auto_select: FALSE
+)]
 class Upload extends WidgetBase {
 
   /**
diff --git a/src/Plugin/EntityBrowser/Widget/View.php b/src/Plugin/EntityBrowser/Widget/View.php
index f445d4579ddeef60af0c26d584afee920a474429..12638d5410292252690e2dcd5cebbd2aa9585e3a 100644
--- a/src/Plugin/EntityBrowser/Widget/View.php
+++ b/src/Plugin/EntityBrowser/Widget/View.php
@@ -6,7 +6,9 @@ use Drupal\Component\Plugin\Exception\PluginNotFoundException;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\Element;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
+use Drupal\entity_browser\Attribute\EntityBrowserWidget;
 use Drupal\entity_browser\WidgetBase;
 use Drupal\views\Entity\View as ViewEntity;
 use Drupal\views\Views;
@@ -14,15 +16,14 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Uses a view to provide entity listing in a browser's widget.
- *
- * @EntityBrowserWidget(
- *   id = "view",
- *   label = @Translation("View"),
- *   provider = "views",
- *   description = @Translation("Uses a view to provide entity listing in a browser's widget."),
- *   auto_select = TRUE
- * )
  */
+#[EntityBrowserWidget(
+  id: 'view',
+  label: new TranslatableMarkup('View'),
+  description: new TranslatableMarkup("Uses a view to provide entity listing in a browser's widget."),
+  auto_select: TRUE,
+  provider: "views",
+)]
 class View extends WidgetBase {
 
   /**
diff --git a/src/Plugin/EntityBrowser/WidgetSelector/DropDown.php b/src/Plugin/EntityBrowser/WidgetSelector/DropDown.php
index 8b71ba5dc1de395dfc43f2147aa5e1eed80a1749..7a12b551a1c6d76b43c9aba7d4426a6327b68c5e 100644
--- a/src/Plugin/EntityBrowser/WidgetSelector/DropDown.php
+++ b/src/Plugin/EntityBrowser/WidgetSelector/DropDown.php
@@ -2,18 +2,19 @@
 
 namespace Drupal\entity_browser\Plugin\EntityBrowser\WidgetSelector;
 
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserWidgetSelector;
 use Drupal\entity_browser\WidgetSelectorBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Displays widgets in a select list.
- *
- * @EntityBrowserWidgetSelector(
- *   id = "drop_down",
- *   label = @Translation("Drop down widget"),
- *   description = @Translation("Displays the widgets in a drop down.")
- * )
  */
+#[EntityBrowserWidgetSelector(
+  id: 'drop_down',
+  label: new TranslatableMarkup('Drop down widget'),
+  description: new TranslatableMarkup("Displays the widgets in a drop down."),
+)]
 class DropDown extends WidgetSelectorBase {
 
   /**
diff --git a/src/Plugin/EntityBrowser/WidgetSelector/Single.php b/src/Plugin/EntityBrowser/WidgetSelector/Single.php
index d86204b719e03de59d41188dc6ad264aa4976fda..a42306394c97da2187c14193ddc4d7c9a8e92513 100644
--- a/src/Plugin/EntityBrowser/WidgetSelector/Single.php
+++ b/src/Plugin/EntityBrowser/WidgetSelector/Single.php
@@ -2,18 +2,19 @@
 
 namespace Drupal\entity_browser\Plugin\EntityBrowser\WidgetSelector;
 
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserWidgetSelector;
 use Drupal\entity_browser\WidgetSelectorBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Displays only first widget.
- *
- * @EntityBrowserWidgetSelector(
- *   id = "single",
- *   label = @Translation("Single widget"),
- *   description = @Translation("Displays only the first configured widget. Use this if you plan to have only one widget available.")
- * )
  */
+#[EntityBrowserWidgetSelector(
+  id: 'single',
+  label: new TranslatableMarkup('Single widget'),
+  description: new TranslatableMarkup("Displays only the first configured widget. Use this if you plan to have only one widget available."),
+)]
 class Single extends WidgetSelectorBase {
 
   /**
diff --git a/src/Plugin/EntityBrowser/WidgetSelector/Tabs.php b/src/Plugin/EntityBrowser/WidgetSelector/Tabs.php
index aad1e56ffb4dcbc0f2189bf284ebd14ee2a61f40..c70356a56cfa4ac4fd5bc6a6836173b791848641 100644
--- a/src/Plugin/EntityBrowser/WidgetSelector/Tabs.php
+++ b/src/Plugin/EntityBrowser/WidgetSelector/Tabs.php
@@ -2,18 +2,19 @@
 
 namespace Drupal\entity_browser\Plugin\EntityBrowser\WidgetSelector;
 
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserWidgetSelector;
 use Drupal\entity_browser\WidgetSelectorBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Displays entity browser widgets as tabs.
- *
- * @EntityBrowserWidgetSelector(
- *   id = "tabs",
- *   label = @Translation("Tabs"),
- *   description = @Translation("Creates horizontal tabs on the top of the entity browser, each tab representing one available widget.")
- * )
  */
+#[EntityBrowserWidgetSelector(
+  id: 'tabs',
+  label: new TranslatableMarkup('Tabs'),
+  description: new TranslatableMarkup("Creates horizontal tabs on the top of the entity browser, each tab representing one available widget."),
+)]
 class Tabs extends WidgetSelectorBase {
 
   /**
diff --git a/src/Plugin/EntityBrowser/WidgetValidation/Cardinality.php b/src/Plugin/EntityBrowser/WidgetValidation/Cardinality.php
index e26d3f6ec2a1666eeab9a0d06c56d21615374be9..d7a8c877816cfe69890cd1aa583ba5acf14616fc 100644
--- a/src/Plugin/EntityBrowser/WidgetValidation/Cardinality.php
+++ b/src/Plugin/EntityBrowser/WidgetValidation/Cardinality.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\entity_browser\Plugin\EntityBrowser\WidgetValidation;
 
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserWidgetValidation;
 use Drupal\entity_browser\Element\EntityBrowserElement;
 use Drupal\entity_browser\WidgetValidationBase;
 use Symfony\Component\Validator\ConstraintViolation;
@@ -9,12 +11,11 @@ use Symfony\Component\Validator\ConstraintViolationList;
 
 /**
  * Validates that the widget returns the appropriate number of elements.
- *
- * @EntityBrowserWidgetValidation(
- *   id = "cardinality",
- *   label = @Translation("Cardinality validator")
- * )
  */
+#[EntityBrowserWidgetValidation(
+  id: 'cardinality',
+  label: new TranslatableMarkup('Cardinality validator'),
+)]
 class Cardinality extends WidgetValidationBase {
 
   /**
diff --git a/src/Plugin/EntityBrowser/WidgetValidation/EntityType.php b/src/Plugin/EntityBrowser/WidgetValidation/EntityType.php
index 1b32e471d0e2b0b6d3245657462f72a885007019..69fd4e7a98abfb713bd456e61e0b103083183b60 100644
--- a/src/Plugin/EntityBrowser/WidgetValidation/EntityType.php
+++ b/src/Plugin/EntityBrowser/WidgetValidation/EntityType.php
@@ -2,16 +2,17 @@
 
 namespace Drupal\entity_browser\Plugin\EntityBrowser\WidgetValidation;
 
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserWidgetValidation;
 use Drupal\entity_browser\WidgetValidationBase;
 
 /**
  * Validates that each passed Entity is of the correct type.
- *
- * @EntityBrowserWidgetValidation(
- *   id = "entity_type",
- *   label = @Translation("Entity type validator"),
- *   data_type = "entity_reference",
- *   constraint = "EntityType"
- * )
  */
+#[EntityBrowserWidgetValidation(
+  id: 'entity_type',
+  label: new TranslatableMarkup('Entity type validator'),
+  data_type: 'entity_reference',
+  constraint: 'EntityType'
+)]
 class EntityType extends WidgetValidationBase {}
diff --git a/src/Plugin/EntityBrowser/WidgetValidation/File.php b/src/Plugin/EntityBrowser/WidgetValidation/File.php
index f2f763c43728bb22be0a764acd860d032baa2289..d76d564e59dea1c1fd454cceb24560effab603cb 100644
--- a/src/Plugin/EntityBrowser/WidgetValidation/File.php
+++ b/src/Plugin/EntityBrowser/WidgetValidation/File.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\entity_browser\Plugin\EntityBrowser\WidgetValidation;
 
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_browser\Attribute\EntityBrowserWidgetValidation;
 use Drupal\entity_browser\WidgetValidationBase;
 use Drupal\file\Validation\FileValidatorInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -10,12 +12,11 @@ use Symfony\Component\Validator\ConstraintViolationList;
 
 /**
  * Validates a file based on passed validators.
- *
- * @EntityBrowserWidgetValidation(
- *   id = "file",
- *   label = @Translation("File validator")
- * )
  */
+#[EntityBrowserWidgetValidation(
+  id: 'file',
+  label: new TranslatableMarkup('File validator'),
+)]
 class File extends WidgetValidationBase {
 
   /**
diff --git a/src/SelectionDisplayManager.php b/src/SelectionDisplayManager.php
index 537d9f8b6860b5559adbee35d34213e46b01035d..e5dffe0ab6a63f7d4e93a5262b4180533df2d0f0 100644
--- a/src/SelectionDisplayManager.php
+++ b/src/SelectionDisplayManager.php
@@ -23,7 +23,7 @@ class SelectionDisplayManager extends DefaultPluginManager {
    *   The module handler.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/EntityBrowser/SelectionDisplay', $namespaces, $module_handler, 'Drupal\entity_browser\SelectionDisplayInterface', 'Drupal\entity_browser\Annotation\EntityBrowserSelectionDisplay');
+    parent::__construct('Plugin/EntityBrowser/SelectionDisplay', $namespaces, $module_handler, 'Drupal\entity_browser\SelectionDisplayInterface', 'Drupal\entity_browser\Attribute\EntityBrowserSelectionDisplay', 'Drupal\entity_browser\Annotation\EntityBrowserSelectionDisplay');
 
     $this->alterInfo('entity_browser_selection_display_info');
     $this->setCacheBackend($cache_backend, 'entity_browser_selection_display_plugins');
diff --git a/src/WidgetManager.php b/src/WidgetManager.php
index 04557a00521335839a49b92daf02b1c199908e84..9db9eee9ae733f50750fc8a13e556c42a8c99158 100644
--- a/src/WidgetManager.php
+++ b/src/WidgetManager.php
@@ -23,7 +23,7 @@ class WidgetManager extends DefaultPluginManager {
    *   The module handler.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/EntityBrowser/Widget', $namespaces, $module_handler, 'Drupal\entity_browser\WidgetInterface', 'Drupal\entity_browser\Annotation\EntityBrowserWidget');
+    parent::__construct('Plugin/EntityBrowser/Widget', $namespaces, $module_handler, 'Drupal\entity_browser\WidgetInterface', 'Drupal\entity_browser\Attribute\EntityBrowserWidget', 'Drupal\entity_browser\Annotation\EntityBrowserWidget');
 
     $this->alterInfo('entity_browser_widget_info');
     $this->setCacheBackend($cache_backend, 'entity_browser_widget_plugins');
diff --git a/src/WidgetSelectorManager.php b/src/WidgetSelectorManager.php
index b5d2f516abf5929abdc74239f603b5aeadc5d6fc..a7373062310672edbfdd0167b87bf50bd5b617ac 100644
--- a/src/WidgetSelectorManager.php
+++ b/src/WidgetSelectorManager.php
@@ -23,7 +23,7 @@ class WidgetSelectorManager extends DefaultPluginManager {
    *   The module handler.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/EntityBrowser/WidgetSelector', $namespaces, $module_handler, 'Drupal\entity_browser\WidgetSelectorInterface', 'Drupal\entity_browser\Annotation\EntityBrowserWidgetSelector');
+    parent::__construct('Plugin/EntityBrowser/WidgetSelector', $namespaces, $module_handler, 'Drupal\entity_browser\WidgetSelectorInterface', 'Drupal\entity_browser\Attribute\EntityBrowserWidgetSelector', 'Drupal\entity_browser\Annotation\EntityBrowserWidgetSelector');
 
     $this->alterInfo('entity_browser_widget_selector_info');
     $this->setCacheBackend($cache_backend, 'entity_browser_widget_selector_plugins');
diff --git a/src/WidgetValidationManager.php b/src/WidgetValidationManager.php
index eb8a6a6da0f2acdd5aa21e3cc1532d74d9f58689..26f00ddb2727a176dc7ed6434d851be616868a38 100644
--- a/src/WidgetValidationManager.php
+++ b/src/WidgetValidationManager.php
@@ -23,7 +23,7 @@ class WidgetValidationManager extends DefaultPluginManager {
    *   The module handler.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/EntityBrowser/WidgetValidation', $namespaces, $module_handler, 'Drupal\entity_browser\WidgetValidationInterface', 'Drupal\entity_browser\Annotation\EntityBrowserWidgetValidation');
+    parent::__construct('Plugin/EntityBrowser/WidgetValidation', $namespaces, $module_handler, 'Drupal\entity_browser\WidgetValidationInterface', 'Drupal\entity_browser\Attribute\EntityBrowserWidgetValidation', 'Drupal\entity_browser\Annotation\EntityBrowserWidgetValidation');
 
     $this->alterInfo('entity_browser_widget_validation_info');
     $this->setCacheBackend($cache_backend, 'entity_browser_widget_validation_plugins');