diff --git a/modules/promotion/commerce_promotion.libraries.yml b/modules/promotion/commerce_promotion.libraries.yml
index 3ff5b7d..f35b296 100644
--- a/modules/promotion/commerce_promotion.libraries.yml
+++ b/modules/promotion/commerce_promotion.libraries.yml
@@ -3,3 +3,11 @@ form:
   css:
     theme:
       css/promotion.form.css: {}
+
+coupon_redemption_form:
+  version: VERSION
+  js:
+    js/coupon-redemption-form.js: {}
+  dependencies:
+    - core/jquery
+    - core/drupal
diff --git a/modules/promotion/js/coupon-redemption-form.js b/modules/promotion/js/coupon-redemption-form.js
new file mode 100644
index 0000000..a5d5ab3
--- /dev/null
+++ b/modules/promotion/js/coupon-redemption-form.js
@@ -0,0 +1,33 @@
+/**
+ * @file
+ * Defines behaviors for the coupon redemption form.
+ */
+(function ($, Drupal, drupalSettings) {
+
+  'use strict';
+
+  /**
+   * Attaches the commerceCouponRedemptionForm behavior.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the commerceCouponRedemptionForm behavior.
+   */
+  Drupal.behaviors.commerceCouponRedemptionForm = {
+    attach: function (context) {
+      // Show coupon code form on link click.
+      $('.show-coupon-code-form', context).on('click', function (e) {
+        $(this).next('#coupon-code-form').removeClass('hidden');
+        $(this).hide();
+        e.preventDefault();
+      });
+      // Show coupon code form on validation error.
+      if ($('#coupon-code-form input[type=text]', context).hasClass('error')) {
+        $('#coupon-code-form').removeClass('hidden');
+        $('.show-coupon-code-form').hide();
+      }
+    }
+  };
+
+})(jQuery, Drupal, drupalSettings);
diff --git a/modules/promotion/templates/commerce-coupon-redemption-form.html.twig b/modules/promotion/templates/commerce-coupon-redemption-form.html.twig
index c71818b..65f7ab2 100644
--- a/modules/promotion/templates/commerce-coupon-redemption-form.html.twig
+++ b/modules/promotion/templates/commerce-coupon-redemption-form.html.twig
@@ -34,4 +34,6 @@
   {% endif %}
 {% endif %}
 
-{{ form|without('coupons') }}
+{{ attach_library('commerce_promotion/coupon_redemption_form') }}
+<a href="#" class="show-coupon-code-form"> {{ 'Did you receive a coupon code?'|t }} </a>
+<div id="coupon-code-form" class="hidden">{{ form|without('coupons') }}</div>
diff --git a/modules/promotion/tests/src/FunctionalJavascript/CouponRedemptionElementTest.php b/modules/promotion/tests/src/FunctionalJavascript/CouponRedemptionElementTest.php
index 6b58f26..e9c7848 100644
--- a/modules/promotion/tests/src/FunctionalJavascript/CouponRedemptionElementTest.php
+++ b/modules/promotion/tests/src/FunctionalJavascript/CouponRedemptionElementTest.php
@@ -114,6 +114,12 @@ class CouponRedemptionElementTest extends CommerceBrowserTestBase {
 
     $this->drupalGet(Url::fromRoute('commerce_cart.page', [], ['query' => ['coupon_cardinality' => 1]]));
     $this->assertSession()->pageTextContains('Enter your coupon code to redeem a promotion.');
+    // Coupon code form not visible by default.
+    $coupon_button = $this->getSession()->getPage()->findButton('Apply coupon');
+    $this->assertNotTrue($coupon_button->isVisible());
+    $this->getSession()->getPage()->clickLink('Did you receive a coupon code?');
+    $this->assertSession()->fieldNotExists('Did you receive a coupon code?');
+
     // Empty coupon.
     $this->getSession()->getPage()->pressButton('Apply coupon');
     $this->waitForAjaxToFinish();
@@ -152,6 +158,7 @@ class CouponRedemptionElementTest extends CommerceBrowserTestBase {
     $second_coupon = end($coupons);
 
     $this->drupalGet(Url::fromRoute('commerce_cart.page', [], ['query' => ['coupon_cardinality' => 2]]));
+    $this->getSession()->getPage()->clickLink('Did you receive a coupon code?');
     // First coupon.
     $this->getSession()->getPage()->fillField('Coupon code', $first_coupon->getCode());
     $this->getSession()->getPage()->pressButton('Apply coupon');
@@ -161,6 +168,12 @@ class CouponRedemptionElementTest extends CommerceBrowserTestBase {
     // The coupon code input field needs to be cleared.
     $this->assertSession()->fieldValueNotEquals('Coupon code', $first_coupon->getCode());
 
+    // Coupon code form not visible by default every time.
+    $coupon_button = $this->getSession()->getPage()->findButton('Apply coupon');
+    $this->assertNotTrue($coupon_button->isVisible());
+    $this->getSession()->getPage()->clickLink('Did you receive a coupon code?');
+    $this->assertSession()->fieldNotExists('Did you receive a coupon code?');
+
     // First coupon, applied for the second time.
     $this->getSession()->getPage()->fillField('Coupon code', $first_coupon->getCode());
     $this->getSession()->getPage()->pressButton('Apply coupon');
@@ -168,6 +181,7 @@ class CouponRedemptionElementTest extends CommerceBrowserTestBase {
     $this->assertSession()->pageTextContains('The provided coupon code is invalid');
 
     // Second coupon.
+    // The coupon code form is visible as we are here in a "validation" state.
     $this->getSession()->getPage()->fillField('Coupon code', $second_coupon->getCode());
     $this->getSession()->getPage()->pressButton('Apply coupon');
     $this->waitForAjaxToFinish();
diff --git a/modules/promotion/tests/src/FunctionalJavascript/CouponRedemptionPaneTest.php b/modules/promotion/tests/src/FunctionalJavascript/CouponRedemptionPaneTest.php
index 3faa3ba..705f60a 100644
--- a/modules/promotion/tests/src/FunctionalJavascript/CouponRedemptionPaneTest.php
+++ b/modules/promotion/tests/src/FunctionalJavascript/CouponRedemptionPaneTest.php
@@ -171,6 +171,13 @@ class CouponRedemptionPaneTest extends CommerceBrowserTestBase {
     $coupon = reset($coupons);
 
     $this->drupalGet(Url::fromRoute('commerce_checkout.form', ['commerce_order' => $this->cart->id()]));
+
+    // Coupon code form not visible by default.
+    $coupon_button = $this->getSession()->getPage()->findButton('Apply coupon');
+    $this->assertNotTrue($coupon_button->isVisible());
+    $this->getSession()->getPage()->clickLink('Did you receive a coupon code?');
+    $this->assertSession()->fieldNotExists('Did you receive a coupon code?');
+
     // Confirm that validation errors set by the form element are visible.
     $this->getSession()->getPage()->pressButton('Apply coupon');
     $this->waitForAjaxToFinish();
@@ -207,6 +214,7 @@ class CouponRedemptionPaneTest extends CommerceBrowserTestBase {
     $coupon = reset($coupons);
 
     $this->drupalGet(Url::fromRoute('commerce_checkout.form', ['commerce_order' => $this->cart->id()]));
+    $this->getSession()->getPage()->clickLink('Did you receive a coupon code?');
     $this->getSession()->getPage()->fillField('Coupon code', $coupon->getCode());
     $this->getSession()->getPage()->pressButton('Apply coupon');
     $this->waitForAjaxToFinish();
@@ -228,6 +236,7 @@ class CouponRedemptionPaneTest extends CommerceBrowserTestBase {
     $coupon = reset($coupons);
     $this->drupalGet(Url::fromRoute('commerce_checkout.form', ['commerce_order' => $this->cart->id()]));
 
+    $this->getSession()->getPage()->clickLink('Did you receive a coupon code?');
     $this->getSession()->getPage()->fillField('Coupon code', $coupon->getCode());
     $this->getSession()->getPage()->pressButton('Apply coupon');
     $this->waitForAjaxToFinish();
@@ -263,9 +272,10 @@ class CouponRedemptionPaneTest extends CommerceBrowserTestBase {
     $coupon = reset($coupons);
     $this->drupalGet(Url::fromRoute('commerce_checkout.form', ['commerce_order' => $this->cart->id()]));
 
+    $this->getSession()->getPage()->clickLink('Did you receive a coupon code?');
     $this->getSession()->getPage()->fillField('Coupon code', $coupon->getCode());
     $this->submitForm([], 'Continue to review');
-    $this->assertSession()->pageTextContains('Visa ending in 1111');
+    $this->assertSession()->pageTextContains('Visa ending in 9999');
     $this->assertSession()->pageTextContains($coupon->getCode());
     $this->assertSession()->pageTextContains('-$99.90');
     $this->assertSession()->pageTextContains('$899.10');
@@ -306,6 +316,7 @@ class CouponRedemptionPaneTest extends CommerceBrowserTestBase {
     $coupons = $this->promotion->getCoupons();
     $coupon = reset($coupons);
     $page = $this->getSession()->getPage();
+    $this->getSession()->getPage()->clickLink('Did you receive a coupon code?');
     $page->fillField('Coupon code', $coupon->getCode());
     $page->pressButton('Apply coupon');
     $this->waitForAjaxToFinish();
