diff --git a/core/modules/book/src/Plugin/views/argument_default/TopLevelBook.php b/core/modules/book/src/Plugin/views/argument_default/TopLevelBook.php
index 36a6f79a5ca334f01bb763937f00b6799b79698e..291ad1c2bafcab38f6eccac0779328566fe07b33 100644
--- a/core/modules/book/src/Plugin/views/argument_default/TopLevelBook.php
+++ b/core/modules/book/src/Plugin/views/argument_default/TopLevelBook.php
@@ -3,18 +3,19 @@
 namespace Drupal\book\Plugin\views\argument_default;
 
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\node\NodeStorageInterface;
 use Drupal\node\Plugin\views\argument_default\Node;
+use Drupal\views\Attribute\ViewsArgumentDefault;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Default argument plugin to get the current node's top level book.
- *
- * @ViewsArgumentDefault(
- *   id = "top_level_book",
- *   title = @Translation("Top Level Book from current node")
- * )
  */
+#[ViewsArgumentDefault(
+  id: 'top_level_book',
+  title: new TranslatableMarkup('Top Level Book from current node"'),
+)]
 class TopLevelBook extends Node {
 
   /**
diff --git a/core/modules/node/src/Plugin/views/argument_default/Node.php b/core/modules/node/src/Plugin/views/argument_default/Node.php
index adb3bd3ef7e29b86255cde2fc01cf0b1ecb20e94..687322d05c3197d6c98a4e1f28832cc6f1e14d0f 100644
--- a/core/modules/node/src/Plugin/views/argument_default/Node.php
+++ b/core/modules/node/src/Plugin/views/argument_default/Node.php
@@ -5,18 +5,19 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\views\Attribute\ViewsArgumentDefault;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 use Drupal\node\NodeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Default argument plugin to extract a node.
- *
- * @ViewsArgumentDefault(
- *   id = "node",
- *   title = @Translation("Content ID from URL")
- * )
  */
+#[ViewsArgumentDefault(
+  id: 'node',
+  title: new TranslatableMarkup('Content ID from URL'),
+)]
 class Node extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
diff --git a/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php b/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
index cf9bcd64a73e20a3ee0c226208b940fbcb111bdc..cb152999db6d17834f098fb6ce8c70add62ca887 100644
--- a/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
+++ b/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
@@ -6,7 +6,9 @@
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\taxonomy\TermInterface;
+use Drupal\views\Attribute\ViewsArgumentDefault;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 use Drupal\node\NodeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -14,12 +16,11 @@
 
 /**
  * Taxonomy tid default argument.
- *
- * @ViewsArgumentDefault(
- *   id = "taxonomy_tid",
- *   title = @Translation("Taxonomy term ID from URL")
- * )
  */
+#[ViewsArgumentDefault(
+  id: 'taxonomy_tid',
+  title: new TranslatableMarkup('Taxonomy term ID from URL'),
+)]
 class Tid extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
diff --git a/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php b/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php
index 251d47198bc01a6943cececa7161f1fc40b33cbb..b8d4a99bfa9d3ec61b3c341b2f05df705a76b4b7 100644
--- a/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php
+++ b/core/modules/user/src/Plugin/views/argument_default/CurrentUser.php
@@ -4,18 +4,19 @@
 
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Cache\CacheableDependencyInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\views\Attribute\ViewsArgumentDefault;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 
 /**
  * Default argument plugin to extract the current user.
  *
  * This plugin actually has no options so it does not need to do a great deal.
- *
- * @ViewsArgumentDefault(
- *   id = "current_user",
- *   title = @Translation("User ID from logged in user")
- * )
  */
+#[ViewsArgumentDefault(
+  id: 'current_user',
+  title: new TranslatableMarkup('User ID from logged in user'),
+)]
 class CurrentUser extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
diff --git a/core/modules/user/src/Plugin/views/argument_default/User.php b/core/modules/user/src/Plugin/views/argument_default/User.php
index 3a4aa06c3c000f5b4037e1db190c2c6da4199103..dcaa46c15eec1a6f72e62fb02c7e1394b40306ed 100644
--- a/core/modules/user/src/Plugin/views/argument_default/User.php
+++ b/core/modules/user/src/Plugin/views/argument_default/User.php
@@ -6,6 +6,8 @@
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\views\Attribute\ViewsArgumentDefault;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\user\UserInterface;
@@ -13,12 +15,11 @@
 
 /**
  * Default argument plugin to extract a user from request.
- *
- * @ViewsArgumentDefault(
- *   id = "user",
- *   title = @Translation("User ID from route context")
- * )
  */
+#[ViewsArgumentDefault(
+  id: 'user',
+  title: new TranslatableMarkup('User ID from route context"'),
+)]
 class User extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
diff --git a/core/modules/views/src/Attribute/ViewsArgumentDefault.php b/core/modules/views/src/Attribute/ViewsArgumentDefault.php
new file mode 100644
index 0000000000000000000000000000000000000000..71195ab8b2477dd2c118036314c11eacb3dd2575
--- /dev/null
+++ b/core/modules/views/src/Attribute/ViewsArgumentDefault.php
@@ -0,0 +1,43 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\views\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines a ViewsArgument attribute for plugin discovery.
+ *
+ * @see \Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase
+ *
+ * @ingroup views_argument_default_plugins
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class ViewsArgumentDefault extends Plugin {
+
+  /**
+   * Constructs a ViewsArgument attribute.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $title
+   *   The plugin title used in the views UI
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $short_title
+   *   (optional) The short title used in the views UI.
+   * @param bool $no_ui
+   *   (optional) Whether the plugin should be not selectable in the UI. If it's
+   *   set to TRUE, you can still use it via the API in config files.
+   * @param class-string|null $deriver
+   *   (optional) The deriver class.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly ?TranslatableMarkup $title = NULL,
+    public readonly ?TranslatableMarkup $short_title = NULL,
+    public readonly bool $no_ui = FALSE,
+    public readonly ?string $deriver = NULL
+  ) {}
+
+}
diff --git a/core/modules/views/src/Plugin/views/argument_default/ArgumentDefaultPluginBase.php b/core/modules/views/src/Plugin/views/argument_default/ArgumentDefaultPluginBase.php
index 7cd85a6175c12c39830182b3964a26eaedafe303..25302114a84fad92fa989b44b5f91141ccd33730 100644
--- a/core/modules/views/src/Plugin/views/argument_default/ArgumentDefaultPluginBase.php
+++ b/core/modules/views/src/Plugin/views/argument_default/ArgumentDefaultPluginBase.php
@@ -17,8 +17,8 @@
  *
  * Argument default plugins extend
  * \Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase. They
- * must be annotated with \Drupal\views\Annotation\ViewsArgumentDefault
- * annotation, and they must be in namespace directory
+ * must be attributed with \Drupal\views\Attribute\ViewsArgumentDefault
+ * attribute, and they must be in namespace directory
  * Plugin\views\argument_default.
  *
  * @ingroup views_plugins
diff --git a/core/modules/views/src/Plugin/views/argument_default/Fixed.php b/core/modules/views/src/Plugin/views/argument_default/Fixed.php
index da08e561f0fa06cbcca66736a99a3ba368390c83..3480199c052ceaaaee224beee3c3a7e9c9ca56c5 100644
--- a/core/modules/views/src/Plugin/views/argument_default/Fixed.php
+++ b/core/modules/views/src/Plugin/views/argument_default/Fixed.php
@@ -5,17 +5,19 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\views\Attribute\ViewsArgumentDefault;
 
 /**
  * The fixed argument default handler.
  *
  * @ingroup views_argument_default_plugins
- *
- * @ViewsArgumentDefault(
- *   id = "fixed",
- *   title = @Translation("Fixed")
  * )
  */
+#[ViewsArgumentDefault(
+  id: 'fixed',
+  title: new TranslatableMarkup('Fixed'),
+)]
 class Fixed extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
diff --git a/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php b/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
index 5370e4e14947b019540692ab3e33afac8c2b381e..bd7df1cd7cbdf343ef9744ab7defca5cc363b99c 100644
--- a/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
+++ b/core/modules/views/src/Plugin/views/argument_default/QueryParameter.php
@@ -6,17 +6,18 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\views\Attribute\ViewsArgumentDefault;
 
 /**
  * A query parameter argument default handler.
  *
  * @ingroup views_argument_default_plugins
- *
- * @ViewsArgumentDefault(
- *   id = "query_parameter",
- *   title = @Translation("Query parameter")
- * )
  */
+#[ViewsArgumentDefault(
+  id: 'query_parameter',
+  title: new TranslatableMarkup('Query parameter'),
+)]
 class QueryParameter extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
diff --git a/core/modules/views/src/Plugin/views/argument_default/Raw.php b/core/modules/views/src/Plugin/views/argument_default/Raw.php
index f44215b7fafe3c3c105079e17f1f64ff405e4989..324da297970ef59f6ff4df752060e4182d23ff0a 100644
--- a/core/modules/views/src/Plugin/views/argument_default/Raw.php
+++ b/core/modules/views/src/Plugin/views/argument_default/Raw.php
@@ -6,19 +6,21 @@
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Path\CurrentPathStack;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\path_alias\AliasManagerInterface;
+use Drupal\views\Attribute\ViewsArgumentDefault;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Default argument plugin to use the raw value from the URL.
  *
  * @ingroup views_argument_default_plugins
- *
- * @ViewsArgumentDefault(
- *   id = "raw",
- *   title = @Translation("Raw value from URL")
- * )
  */
+#[ViewsArgumentDefault(
+  id: 'raw',
+  title: new TranslatableMarkup('Raw value from URL'),
+)]
+
 class Raw extends ArgumentDefaultPluginBase implements CacheableDependencyInterface {
 
   /**
diff --git a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/argument_default/ArgumentDefaultTest.php b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/argument_default/ArgumentDefaultTest.php
index 3cc81e279d57df2ff4a8e63c306bfc194c06e5dd..15c1600c2341999ec13ddb48f3c3fcdd7eead7ea 100644
--- a/core/modules/views/tests/modules/views_test_data/src/Plugin/views/argument_default/ArgumentDefaultTest.php
+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/argument_default/ArgumentDefaultTest.php
@@ -2,16 +2,17 @@
 
 namespace Drupal\views_test_data\Plugin\views\argument_default;
 
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\views\Attribute\ViewsArgumentDefault;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 
 /**
  * Defines an argument default test plugin.
- *
- * @ViewsArgumentDefault(
- *   id = "argument_default_test",
- *   title = @Translation("Argument default test")
- * )
  */
+#[ViewsArgumentDefault(
+  id: 'argument_default_test',
+  title: new TranslatableMarkup('Argument default test'),
+)]
 class ArgumentDefaultTest extends ArgumentDefaultPluginBase {
 
   /**