diff --git a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
index 8c6816d8dedec802ec74c524f09be4a6364ebb0a..3d6d80f622b2720c939ef71406ddf0332e8e3c47 100644
--- a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
+++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
@@ -229,6 +229,20 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       $element['uri']['#description'] = $this->t('This must be an external URL such as %url.', ['%url' => 'http://example.com']);
     }
 
+    // Make uri required on the front-end when title filled-in.
+    if (!$this->isDefaultValueWidget($form_state) && $this->getFieldSetting('title') !== DRUPAL_DISABLED && !$element['uri']['#required']) {
+      $parents = $element['#field_parents'];
+      $parents[] = $this->fieldDefinition->getName();
+      $selector = $root = array_shift($parents);
+      if ($parents) {
+        $selector = $root . '[' . implode('][', $parents) . ']';
+      }
+
+      $element['uri']['#states']['required'] = [
+        ':input[name="' . $selector . '[' . $delta . '][title]"]' => ['filled' => TRUE],
+      ];
+    }
+
     $element['title'] = [
       '#type' => 'textfield',
       '#title' => $this->t('Link text'),
@@ -250,10 +264,9 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
 
       if (!$element['title']['#required']) {
         // Make title required on the front-end when URI filled-in.
-        $field_name = $this->fieldDefinition->getName();
 
         $parents = $element['#field_parents'];
-        $parents[] = $field_name;
+        $parents[] = $this->fieldDefinition->getName();
         $selector = $root = array_shift($parents);
         if ($parents) {
           $selector = $root . '[' . implode('][', $parents) . ']';
diff --git a/core/modules/link/tests/src/FunctionalJavascript/LinkFieldFormStatesTest.php b/core/modules/link/tests/src/FunctionalJavascript/LinkFieldFormStatesTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a7e99f06f7c34d1864ff50db4ae39649492ba489
--- /dev/null
+++ b/core/modules/link/tests/src/FunctionalJavascript/LinkFieldFormStatesTest.php
@@ -0,0 +1,80 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\link\FunctionalJavascript;
+
+use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
+
+/**
+ * Tests link field form states functionality.
+ *
+ * @group link
+ */
+class LinkFieldFormStatesTest extends WebDriverTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'entity_test',
+    'link',
+    'node',
+    'link_test_base_field',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+    $this->drupalLogin($this->drupalCreateUser([
+      'administer entity_test content',
+    ]));
+  }
+
+  /**
+   * @dataProvider linkFieldFormStatesData
+   */
+  public function testLinkFieldFormStates(string $uri, string $title) {
+    $this->drupalGet('entity_test/add');
+    $session = $this->assertSession();
+    $session->elementNotExists('css', '#edit-links-0-uri[required]');
+    $session->elementNotExists('css', '#edit-links-0-title[required]');
+
+    $page = $this->getSession()->getPage();
+
+    if ($uri !== '') {
+      $page->fillField('links[0][uri]', $uri);
+      $session->elementNotExists('css', '#edit-links-0-uri[required]');
+      $session->elementExists('css', '#edit-links-0-title[required]');
+    }
+    else {
+      $page->fillField('links[0][title]', $title);
+      $session->elementExists('css', '#edit-links-0-uri[required]');
+      $session->elementNotExists('css', '#edit-links-0-title[required]');
+    }
+  }
+
+  /**
+   * Provides data for ::testLinkFieldJSFormStates.
+   */
+  public function linkFieldFormStatesData() {
+    return [
+      'Fill uri, keep title empty' => [
+        'https://drupal.org',
+        '',
+      ],
+      'Fill title, keep uri empty' => [
+        '',
+        'https://drupal.org',
+      ],
+    ];
+  }
+
+}