diff --git a/core/misc/cspell/dictionary.txt b/core/misc/cspell/dictionary.txt
index e2aee906ebe1ab769117a8e6524c0297c8f1273f..30a2064e2728d154f34eb788751e9f13c0fad39f 100644
--- a/core/misc/cspell/dictionary.txt
+++ b/core/misc/cspell/dictionary.txt
@@ -366,6 +366,7 @@ pickable
 pingback
 placeholdered
 placeholdering
+playsinline
 plusthick
 porterstemmer
 postcondition
diff --git a/core/modules/file/config/schema/file.schema.yml b/core/modules/file/config/schema/file.schema.yml
index e193063740b7334830647433466f0f78c2b2c2b6..531ef0723b456280c569e008920aa001f97424c9 100644
--- a/core/modules/file/config/schema/file.schema.yml
+++ b/core/modules/file/config/schema/file.schema.yml
@@ -133,6 +133,9 @@ field.formatter.settings.file_video:
     muted:
       type: boolean
       label: 'Muted'
+    playsinline:
+      type: boolean
+      label: 'Plays inline'
     width:
       type: integer
       label: 'Width'
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 120d553c5c6dd943642a94aa5e2f25d83bcb3ca6..f3297f7ba6330ccb5fb5694371a0ae67fac1c4d1 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -23,6 +23,7 @@
 use Drupal\Core\Template\Attribute;
 use Drupal\file\FileInterface;
 use Drupal\file\IconMimeTypes;
+use Drupal\file\Plugin\Field\FieldFormatter\FileVideoFormatter;
 use Drupal\file\Upload\FileUploadHandlerInterface;
 use Drupal\file\Upload\FormUploadedFile;
 
@@ -765,3 +766,12 @@ function file_system_settings_submit(array &$form, FormStateInterface $form_stat
     ->set('filename_sanitization', $form_state->getValue('filename_sanitization'));
   $config->save();
 }
+
+/**
+ * Implements hook_ENTITY_TYPE_presave().
+ */
+function file_file_video_presave(FileVideoFormatter $formatter): void {
+  if ($formatter->getSetting('playsinline') === NULL) {
+    $formatter->setSetting('playsinline', FALSE);
+  }
+}
diff --git a/core/modules/file/file.post_update.php b/core/modules/file/file.post_update.php
index 1c40f237edd1b7f69d9e2f3cc69318c0281d9f2b..b7ecaabff8ae4e744e4f09eb45dc8177e76dd3fc 100644
--- a/core/modules/file/file.post_update.php
+++ b/core/modules/file/file.post_update.php
@@ -5,6 +5,10 @@
  * Post update functions for File.
  */
 
+use Drupal\Core\Config\Entity\ConfigEntityUpdater;
+use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
 /**
  * Implements hook_removed_post_updates().
  */
@@ -15,3 +19,23 @@ function file_removed_post_updates(): array {
     'file_post_update_add_default_filename_sanitization_configuration' => '11.0.0',
   ];
 }
+
+/**
+ * Adds a value for the 'playsinline' setting of the 'file_video' formatter.
+ */
+function file_post_update_add_playsinline(array &$sandbox = []): ?TranslatableMarkup {
+  /** @var \Drupal\Core\Config\Entity\ConfigEntityUpdater $config_entity_updater */
+  $config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
+  return $config_entity_updater->update($sandbox, 'entity_view_display', function (EntityViewDisplayInterface $display) {
+    $needs_update = FALSE;
+    $components = $display->getComponents();
+    foreach ($components as $name => $component) {
+      if (isset($component['type']) && $component['type'] === 'file_video') {
+        $needs_update = TRUE;
+        $component['settings']['playsinline'] = FALSE;
+        $display->setComponent($name, $component);
+      }
+    }
+    return $needs_update;
+  });
+}
diff --git a/core/modules/file/src/Plugin/Field/FieldFormatter/FileVideoFormatter.php b/core/modules/file/src/Plugin/Field/FieldFormatter/FileVideoFormatter.php
index 41966203a374447cbd63e34767053f42fbe071b3..4cf055bccb8fa880ecbe9ef86f2808f1291b7f20 100644
--- a/core/modules/file/src/Plugin/Field/FieldFormatter/FileVideoFormatter.php
+++ b/core/modules/file/src/Plugin/Field/FieldFormatter/FileVideoFormatter.php
@@ -32,6 +32,7 @@ public static function getMediaType() {
   public static function defaultSettings() {
     return [
       'muted' => FALSE,
+      'playsinline' => FALSE,
       'width' => 640,
       'height' => 480,
     ] + parent::defaultSettings();
@@ -47,6 +48,11 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
         '#type' => 'checkbox',
         '#default_value' => $this->getSetting('muted'),
       ],
+      'playsinline' => [
+        '#title' => $this->t('Plays Inline'),
+        '#type' => 'checkbox',
+        '#default_value' => $this->getSetting('playsinline'),
+      ],
       'width' => [
         '#type' => 'number',
         '#title' => $this->t('Width'),
@@ -76,6 +82,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
   public function settingsSummary() {
     $summary = parent::settingsSummary();
     $summary[] = $this->t('Muted: %muted', ['%muted' => $this->getSetting('muted') ? $this->t('yes') : $this->t('no')]);
+    $summary[] = $this->t('Plays Inline: %playsinline', ['%playsinline' => $this->getSetting('playsinline') ? $this->t('yes') : $this->t('no')]);
 
     if ($width = $this->getSetting('width')) {
       $summary[] = $this->t('Width: %width pixels', [
@@ -96,7 +103,7 @@ public function settingsSummary() {
    * {@inheritdoc}
    */
   protected function prepareAttributes(array $additional_attributes = []) {
-    $attributes = parent::prepareAttributes(['muted']);
+    $attributes = parent::prepareAttributes(['muted', 'playsinline']);
     if (($width = $this->getSetting('width'))) {
       $attributes->setAttribute('width', $width);
     }
diff --git a/core/modules/file/tests/fixtures/update/file_post_update_playsinline-3046152.php b/core/modules/file/tests/fixtures/update/file_post_update_playsinline-3046152.php
new file mode 100644
index 0000000000000000000000000000000000000000..876e33ccbb264814d1e31453842e79729b921b82
--- /dev/null
+++ b/core/modules/file/tests/fixtures/update/file_post_update_playsinline-3046152.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @file
+ * Fixture file to test file_post_update_add_playsinline().
+ *
+ * @see https://www.drupal.org/project/drupal/issues/3046152
+ * @see \Drupal\Tests\file\Functional\Formatter\FileVideoFormatterUpdateTest
+ * @see \file_post_update_add_playsinline()
+ */
+
+use Drupal\Component\Serialization\Yaml;
+use Drupal\Core\Database\Database;
+
+$display = Yaml::decode(file_get_contents(__DIR__ . '/post_update_playsinline-3046152-node-article.yml'));
+
+$db = Database::getConnection();
+$db->update('config')
+  ->fields([
+    'data' => serialize($display),
+  ])
+  ->condition('name', 'core.entity_view_display.node.article.default')
+  ->execute();
diff --git a/core/modules/file/tests/fixtures/update/post_update_playsinline-3046152-node-article.yml b/core/modules/file/tests/fixtures/update/post_update_playsinline-3046152-node-article.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8657e1c7667d0eef63695ca26aadb0ca8bb8328a
--- /dev/null
+++ b/core/modules/file/tests/fixtures/update/post_update_playsinline-3046152-node-article.yml
@@ -0,0 +1,80 @@
+# cspell:ignore autoplay
+uuid: 93ccb838-5462-45ee-862a-988b9bdc6e0f
+langcode: en
+status: true
+dependencies:
+  config:
+    - core.entity_view_display.comment.comment.default
+    - field.field.node.article.body
+    - field.field.node.article.comment
+    - field.field.node.article.field_image
+    - field.field.node.article.field_tags
+    - field.field.node.article.field_video
+    - image.style.wide
+    - node.type.article
+  module:
+    - comment
+    - file
+    - image
+    - text
+    - user
+id: node.article.default
+targetEntityType: node
+bundle: article
+mode: default
+content:
+  body:
+    type: text_default
+    label: hidden
+    settings: {  }
+    third_party_settings: {  }
+    weight: 0
+    region: content
+  comment:
+    type: comment_default
+    label: above
+    settings:
+      view_mode: default
+      pager_id: 0
+    third_party_settings: {  }
+    weight: 110
+    region: content
+  field_image:
+    type: image
+    label: hidden
+    settings:
+      image_link: ''
+      image_style: wide
+      image_loading:
+        attribute: eager
+    third_party_settings: {  }
+    weight: -1
+    region: content
+  field_tags:
+    type: entity_reference_label
+    label: above
+    settings:
+      link: true
+    third_party_settings: {  }
+    weight: 10
+    region: content
+  field_video:
+    type: file_video
+    label: above
+    settings:
+      controls: true
+      autoplay: false
+      loop: false
+      multiple_file_display_type: tags
+      muted: true
+      width: 640
+      height: 480
+    third_party_settings: {  }
+    weight: 111
+    region: content
+  links:
+    settings: {  }
+    third_party_settings: {  }
+    weight: 100
+    region: content
+hidden: {  }
diff --git a/core/modules/file/tests/src/Functional/Formatter/FileVideoFormatterTest.php b/core/modules/file/tests/src/Functional/Formatter/FileVideoFormatterTest.php
index 651fefdff9c9166cea7627ca06e1147d15be74a2..d25eedfc0a858686e905bea3563aafe59a1149fd 100644
--- a/core/modules/file/tests/src/Functional/Formatter/FileVideoFormatterTest.php
+++ b/core/modules/file/tests/src/Functional/Formatter/FileVideoFormatterTest.php
@@ -73,6 +73,7 @@ public function testAttributes(): void {
         'autoplay' => TRUE,
         'loop' => TRUE,
         'muted' => TRUE,
+        'playsinline' => TRUE,
         'width' => 800,
         'height' => 600,
       ]
@@ -102,6 +103,7 @@ public function testAttributes(): void {
     $assert_session->elementExists('css', "video[autoplay='autoplay'] > source[src='$file_url'][type='video/mp4']");
     $assert_session->elementExists('css', "video[loop='loop'] > source[src='$file_url'][type='video/mp4']");
     $assert_session->elementExists('css', "video[muted='muted'] > source[src='$file_url'][type='video/mp4']");
+    $assert_session->elementExists('css', "video[playsinline='playsinline'] > source[src='$file_url'][type='video/mp4']");
     $assert_session->elementExists('css', "video[width='800'] > source[src='$file_url'][type='video/mp4']");
     $assert_session->elementExists('css', "video[height='600'] > source[src='$file_url'][type='video/mp4']");
 
diff --git a/core/modules/file/tests/src/Functional/Formatter/FileVideoFormatterUpdateTest.php b/core/modules/file/tests/src/Functional/Formatter/FileVideoFormatterUpdateTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e5d5f31f14c6e12106213797d86477c0295dc031
--- /dev/null
+++ b/core/modules/file/tests/src/Functional/Formatter/FileVideoFormatterUpdateTest.php
@@ -0,0 +1,51 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\file\Functional\Formatter;
+
+use Drupal\FunctionalTests\Update\UpdatePathTestBase;
+
+/**
+ * Tests the upgrade path for video formatters.
+ *
+ * @see file_post_update_add_playsinline()
+ *
+ * @group Update
+ * @group legacy
+ */
+class FileVideoFormatterUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['file', 'media'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles(): void {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-10.3.0.bare.standard.php.gz',
+      __DIR__ . '/../../../fixtures/update/file_post_update_playsinline-3046152.php',
+    ];
+  }
+
+  /**
+   * @covers \file_post_update_add_playsinline
+   */
+  public function testPlaysInlineUpdate(): void {
+    $display = $this->config('core.entity_view_display.node.article.default');
+
+    $settings = $display->get('content.field_video.settings');
+    $this->assertArrayNotHasKey('playsinline', $settings);
+
+    $this->runUpdates();
+
+    $display = $this->config('core.entity_view_display.node.article.default');
+    $settings = $display->get('content.field_video.settings');
+
+    $this->assertFalse($settings['playsinline']);
+  }
+
+}
diff --git a/core/profiles/demo_umami/config/install/core.entity_view_display.media.video.default.yml b/core/profiles/demo_umami/config/install/core.entity_view_display.media.video.default.yml
index b8ea26fd67d14ddb2d3169a422fe08ab0518376b..eb4585ef075391afdcc43c7c8483b0c5a9527d41 100644
--- a/core/profiles/demo_umami/config/install/core.entity_view_display.media.video.default.yml
+++ b/core/profiles/demo_umami/config/install/core.entity_view_display.media.video.default.yml
@@ -21,6 +21,7 @@ content:
       loop: false
       multiple_file_display_type: tags
       muted: false
+      playsinline: false
       width: 640
       height: 480
     third_party_settings: {  }
diff --git a/core/profiles/standard/config/optional/core.entity_view_display.media.video.default.yml b/core/profiles/standard/config/optional/core.entity_view_display.media.video.default.yml
index 5ef0df791b61088cf011ab4d91905bbb46ca5128..b90e5998e88f931881d185e4ac1ac2b960b5c3a5 100644
--- a/core/profiles/standard/config/optional/core.entity_view_display.media.video.default.yml
+++ b/core/profiles/standard/config/optional/core.entity_view_display.media.video.default.yml
@@ -21,6 +21,7 @@ content:
       loop: false
       multiple_file_display_type: tags
       muted: false
+      playsinline: false
       width: 640
       height: 480
     third_party_settings: {  }
diff --git a/core/recipes/local_video_media_type/config/core.entity_view_display.media.video.default.yml b/core/recipes/local_video_media_type/config/core.entity_view_display.media.video.default.yml
index 5ef0df791b61088cf011ab4d91905bbb46ca5128..b90e5998e88f931881d185e4ac1ac2b960b5c3a5 100644
--- a/core/recipes/local_video_media_type/config/core.entity_view_display.media.video.default.yml
+++ b/core/recipes/local_video_media_type/config/core.entity_view_display.media.video.default.yml
@@ -21,6 +21,7 @@ content:
       loop: false
       multiple_file_display_type: tags
       muted: false
+      playsinline: false
       width: 640
       height: 480
     third_party_settings: {  }