Repository: Skyscanner/backpack
Pull request #3818: [BpkLink] Reimplement bpklink using gradient background.
Author: login: isteven-shu
Labels: name: minor
description: Non breaking change
Created: 2025-05-06T15:34:17Z | Merged: 2025-05-08T07:34:09Z

<!--
Thanks for contributing to Backpack :pray:

Please include a description of the changes you are introducing and some screenshots if appropriate.

Please ensure your pull request title is clear as it will be used to generate the changelog.

Add `major`, `minor` or `patch` label depending on the change according to [semver](semver.org) or `skip-changelog` if the change shouldn't be added to the changelog (e.g. a change to a test or documentation)
-->
Reimplement bpklink using gradient background instead of `::after`.
https://www.figma.com/design/OplP0YPdKEpf3zsyztsW7j/Bpk-Inline-Link?node-id=933-5618&p=f&t=jtDebc5xDIMYoigl-0


Remember to include the following changes:

- [x] Ensure the PR title includes the name of the component you are changing so it's clear in the release notes for consumers of the changes in the version e.g `[Clover-123][BpkButton] Updating the colour`
- [ ] `README.md` (If you have created a new component)
- [ ] Component `README.md`
- [ ] Tests
- [ ] Accessibility tests
    - The following checks were performed:
        - [ ] Ability to navigate using a [keyboard only](https://webaim.org/techniques/keyboard/)
        - [ ] Zoom functionality ([Deque University explanation](https://dequeuniversity.com/checklists/web/text)):
            - [ ] The page SHOULD be functional AND readable when only the text is magnified to 200% of its initial size
            - [ ] Pages must reflow as zoom increases up to 400% so that content continues to be presented in only one column i.e. Content MUST NOT require scrolling in two directions (both vertically and horizontally)
        - [ ] Ability to navigate using a [screen reader only](https://webaim.org/articles/screenreader_testing/)
- [ ] Storybook examples created/updated
- [ ] For breaking changes or deprecating components/properties, migration guides added to the description of the PR. If the guide has large changes, consider creating a new Markdown page inside the component's docs folder and link it here



Diff:
diff --git a/examples/bpk-component-link/examples.js b/examples/bpk-component-link/examples.js
index 9a922c9465..40e2d6d775 100644
--- a/examples/bpk-component-link/examples.js
+++ b/examples/bpk-component-link/examples.js
@@ -54,6 +54,29 @@ const ImplicitLinkExample = () => (
   </div>
 );
 
+const LinkInGridExample = () => (
+  <div style={{
+    display: 'grid',
+    gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))',
+    gap: '1.5rem',
+    width: '100%',
+    maxWidth: '800px',
+  }}>
+    <BpkLink href="#" onClick={action('#1 clicked')}>
+      Link #1
+    </BpkLink>
+    <BpkLink href="#" onClick={action('#2 clicked')}>
+      Link #2
+    </BpkLink>
+    <BpkLink href="#" onClick={action('#3 clicked')}>
+      Link #3
+    </BpkLink>
+    <BpkLink href="#" onClick={action('#5 clicked')}>
+      Link #4
+    </BpkLink>
+  </div>
+)
+
 const ButtonLinkExample = () => (
   <div>
     <BpkButtonLink onClick={action('#1 clicked')}>Link #1</BpkButtonLink>
@@ -62,6 +85,14 @@ const ButtonLinkExample = () => (
   </div>
 );
 
+const ImplicitButtonLinkExample = () => (
+  <div>
+    <BpkButtonLink onClick={action('#1 clicked')} implicit>Link #1</BpkButtonLink>
+    <br />
+    <BpkButtonLink onClick={action('#2 clicked')} implicit>Link #2</BpkButtonLink>
+  </div>
+);
+
 const LinkAlternativeExample = () => (
   <BpkDarkExampleWrapper>
     <BpkLink href="#" onClick={action('#1 clicked')} alternate>
@@ -108,11 +139,11 @@ const CombinedExample = () => (
 const CombinedAlternativeExample = () => (
   <BpkDarkExampleWrapper style={{ color: colorSkyGrayTint04 }}>
     Links can be both{' '}
-    <BpkLink href="#" style={{ color: colorWhite }}>
+    <BpkLink href="#" alternate>
       anchor tags
     </BpkLink>{' '}
     as well as{' '}
-    <BpkButtonLink onClick={() => null} style={{ color: colorWhite }}>
+    <BpkButtonLink onClick={() => null} alternate>
       button tags
     </BpkButtonLink>
     .
@@ -156,4 +187,6 @@ export {
   CombinedAlternativeExample,
   OverviewExample,
   MixedExample,
+  LinkInGridExample,
+  ImplicitButtonLinkExample,
 };
diff --git a/examples/bpk-component-link/stories.js b/examples/bpk-component-link/stories.js
index 8775138d24..56fde4b435 100644
--- a/examples/bpk-component-link/stories.js
+++ b/examples/bpk-component-link/stories.js
@@ -31,6 +31,8 @@ import {
   CombinedAlternativeExample,
   OverviewExample,
   MixedExample,
+  LinkInGridExample,
+  ImplicitButtonLinkExample,
 } from './examples';
 
 export default {
@@ -43,7 +45,9 @@ export default {
 
 export const Example = LinkExample;
 export const ExampleImplicit = ImplicitLinkExample;
+export const ExampleLinksInGrid = LinkInGridExample;
 export const ExampleButtons = ButtonLinkExample;
+export const ExampleImlicitButtons = ImplicitButtonLinkExample;
 
 export const ExampleAlternate = LinkAlternativeExample;
 export const ExampleAlternateImplicit = LinkAlternativeImplicitExample;
diff --git a/packages/bpk-component-breadcrumb/src/__snapshots__/BpkBreadcrumbItem-test.js.snap b/packages/bpk-component-breadcrumb/src/__snapshots__/BpkBreadcrumbItem-test.js.snap
index 4a1afdd990..9bcb023edd 100644
--- a/packages/bpk-component-breadcrumb/src/__snapshots__/BpkBreadcrumbItem-test.js.snap
+++ b/packages/bpk-component-breadcrumb/src/__snapshots__/BpkBreadcrumbItem-test.js.snap
@@ -12,7 +12,11 @@ exports[`BpkBreadcrumbItem should render correctly 1`] = `
         class="bpk-link"
         href="https://skyscanner.design/"
       >
-        Backpack
+        <span
+          class="bpk-link-underlined"
+        >
+          Backpack
+        </span>
       </a>
     </div>
     <div
@@ -69,7 +73,11 @@ exports[`BpkBreadcrumbItem should render correctly with a custom class name 1`]
         class="bpk-link"
         href="https://skyscanner.design/"
       >
-        Backpack
+        <span
+          class="bpk-link-underlined"
+        >
+          Backpack
+        </span>
       </a>
     </div>
     <div
@@ -105,7 +113,11 @@ exports[`BpkBreadcrumbItem should render correctly with arbitrary props 1`] = `
         class="bpk-link"
         href="https://skyscanner.design/"
       >
-        Backpack
+        <span
+          class="bpk-link-underlined"
+        >
+          Backpack
+        </span>
       </a>
     </div>
     <div
@@ -141,7 +153,11 @@ exports[`BpkBreadcrumbItem should render correctly with with "linkProps" attribu
         href="https://skyscanner.design/"
         testid="arbitrary value"
       >
-        Backpack
+        <span
+          class="bpk-link-underlined"
+        >
+          Backpack
+        </span>
       </a>
     </div>
     <div
diff --git a/packages/bpk-component-grid-toggle/src/__snapshots__/BpkGridToggle-test.js.snap b/packages/bpk-component-grid-toggle/src/__snapshots__/BpkGridToggle-test.js.snap
index a5cd630c0f..94825bb7f3 100644
--- a/packages/bpk-component-grid-toggle/src/__snapshots__/BpkGridToggle-test.js.snap
+++ b/packages/bpk-component-grid-toggle/src/__snapshots__/BpkGridToggle-test.js.snap
@@ -8,7 +8,11 @@ exports[`BpkGridToggle should render correctly 1`] = `
       title="Keyboard Shortcut: ctrl + cmd + g"
       type="button"
     >
-      Baseline grid on
+      <span
+        class="bpk-link-underlined"
+      >
+        Baseline grid on
+      </span>
     </button>
   </span>
 </DocumentFragment>
@@ -24,7 +28,11 @@ exports[`BpkGridToggle should render correctly with the className prop 1`] = `
       title="Keyboard Shortcut: ctrl + cmd + g"
       type="button"
     >
-      Baseline grid on
+      <span
+        class="bpk-link-underlined"
+      >
+        Baseline grid on
+      </span>
     </button>
   </span>
 </DocumentFragment>
diff --git a/packages/bpk-component-link/src/BpkButtonLink.js b/packages/bpk-component-link/src/BpkButtonLink.js
index 2f95bdad51..46be19a021 100644
--- a/packages/bpk-component-link/src/BpkButtonLink.js
+++ b/packages/bpk-component-link/src/BpkButtonLink.js
@@ -34,17 +34,30 @@ type Props = {
   className: ?string,
   onClick: (event: SyntheticEvent<>) => mixed,
   alternate: boolean,
+  implicit?: boolean;
 };
 
 const BpkButtonLink = (props: Props) => {
-  const { alternate, children, className, onClick, ...rest } = props;
+  const { alternate, children, className, implicit, onClick, ...rest } = props;
   const classNames = [getClassName('bpk-link')];
+  const underlinedClassNames = [getClassName('bpk-link-underlined')];
 
+  if (className) {
+    classNames.push(className);
+  }
+  if (implicit) {
+    classNames.push(getClassName('bpk-link--implicit'));
+  }
   if (alternate) {
     classNames.push(getClassName('bpk-link--alternate'));
   }
-  if (className) {
-    classNames.push(className);
+  
+  if (implicit && !alternate) {
+    underlinedClassNames.push(getClassName('bpk-link-underlined--implicit'));
+  } else if (alternate && !implicit) {
+    underlinedClassNames.push(getClassName('bpk-link-underlined--alternate'));
+  } else if (implicit && alternate) {
+    underlinedClassNames.push(getClassName('bpk-link-underlined-implicit--alternate'));
   }
 
   return (
@@ -55,7 +68,7 @@ const BpkButtonLink = (props: Props) => {
       onClick={onClick}
       {...rest}
     >
-      {children}
+      <span className={underlinedClassNames.join(' ')}>{children}</span>
     </button>
   );
 };
@@ -65,11 +78,13 @@ BpkButtonLink.propTypes = {
   children: PropTypes.node.isRequired,
   className: PropTypes.string,
   alternate: PropTypes.bool,
+  implicit: PropTypes.bool,
 };
 
 BpkButtonLink.defaultProps = {
   className: null,
   alternate: false,
+  implicit: false,
 };
 
 export { themeAttributes };
diff --git a/packages/bpk-component-link/src/BpkLink.js b/packages/bpk-component-link/src/BpkLink.js
index 6d5699fa35..963ac8cac0 100644
--- a/packages/bpk-component-link/src/BpkLink.js
+++ b/packages/bpk-component-link/src/BpkLink.js
@@ -56,6 +56,7 @@ const BpkLink = forwardRef((props: Props, ref) => {
   } = props;
 
   const classNames = [getClassName('bpk-link')];
+  const underlinedClassNames = [getClassName('bpk-link-underlined')];
 
   const target = blank ? '_blank' : null;
   const rel = blank ? propRel || 'noopener noreferrer' : propRel;
@@ -69,6 +70,14 @@ const BpkLink = forwardRef((props: Props, ref) => {
   if (alternate) {
     classNames.push(getClassName('bpk-link--alternate'));
   }
+  
+  if (implicit && !alternate) {
+    underlinedClassNames.push(getClassName('bpk-link-underlined--implicit'));
+  } else if (alternate && !implicit) {
+    underlinedClassNames.push(getClassName('bpk-link-underlined--alternate'));
+  } else if (implicit && alternate) {
+    underlinedClassNames.push(getClassName('bpk-link-underlined-implicit--alternate'));
+  }
 
   return (
     // $FlowFixMe[cannot-spread-inexact] - inexact rest. See 'decisions/flowfixme.md'.
@@ -81,7 +90,7 @@ const BpkLink = forwardRef((props: Props, ref) => {
       ref={ref}
       {...rest}
     >
-      {children}
+      <span className={underlinedClassNames.join(' ')}>{children}</span>
     </a>
   );
 });
diff --git a/packages/bpk-component-link/src/BpkLink.module.scss b/packages/bpk-component-link/src/BpkLink.module.scss
index 1b2dd068b1..23d2f53f4e 100644
--- a/packages/bpk-component-link/src/BpkLink.module.scss
+++ b/packages/bpk-component-link/src/BpkLink.module.scss
@@ -33,3 +33,19 @@
     @include typography.bpk-link--alternate;
   }
 }
+
+.bpk-link-underlined {
+  @include typography.bpk-link-underlined;
+
+  &--implicit {
+    @include typography.bpk-link-underlined--implicit;
+  }
+
+  &--alternate {
+    @include typography.bpk-link-underlined--alternate;
+  }
+
+  &-implicit--alternate {
+    @include typography.bpk-link-underlined-implicit--alternate;
+  }
+}
diff --git a/packages/bpk-component-link/src/__snapshots__/BpkButtonLink-test.js.snap b/packages/bpk-component-link/src/__snapshots__/BpkButtonLink-test.js.snap
index c43baab072..2a9a2d4010 100644
--- a/packages/bpk-component-link/src/__snapshots__/BpkButtonLink-test.js.snap
+++ b/packages/bpk-component-link/src/__snapshots__/BpkButtonLink-test.js.snap
@@ -6,7 +6,11 @@ exports[`BpkButtonLink should render correctly 1`] = `
     class="bpk-link"
     type="button"
   >
-    Link
+    <span
+      class="bpk-link-underlined"
+    >
+      Link
+    </span>
   </button>
 </DocumentFragment>
 `;
@@ -17,7 +21,11 @@ exports[`BpkButtonLink should render correctly with "alternate" attribute 1`] =
     class="bpk-link bpk-link--alternate"
     type="button"
   >
-    Link
+    <span
+      class="bpk-link-underlined bpk-link-underlined--alternate"
+    >
+      Link
+    </span>
   </button>
 </DocumentFragment>
 `;
@@ -28,7 +36,11 @@ exports[`BpkButtonLink should render correctly with a "className" atribute 1`] =
     class="bpk-link test-class"
     type="button"
   >
-    Link
+    <span
+      class="bpk-link-underlined"
+    >
+      Link
+    </span>
   </button>
 </DocumentFragment>
 `;
@@ -40,7 +52,11 @@ exports[`BpkButtonLink should render correctly with arbitrary attributes 1`] = `
     id="test-id"
     type="button"
   >
-    Link
+    <span
+      class="bpk-link-underlined"
+    >
+      Link
+    </span>
   </button>
 </DocumentFragment>
 `;
diff --git a/packages/bpk-component-link/src/__snapshots__/BpkLink-test.js.snap b/packages/bpk-component-link/src/__snapshots__/BpkLink-test.js.snap
index b680e3141a..b8f7aeafcf 100644
--- a/packages/bpk-component-link/src/__snapshots__/BpkLink-test.js.snap
+++ b/packages/bpk-component-link/src/__snapshots__/BpkLink-test.js.snap
@@ -8,7 +8,11 @@ exports[`BpkLink should render correctly with "blank" and "rel" attributes 1`] =
     rel="rel-overwrite"
     target="_blank"
   >
-    Link (new window)
+    <span
+      class="bpk-link-underlined"
+    >
+      Link (new window)
+    </span>
   </a>
 </DocumentFragment>
 `;
@@ -19,7 +23,11 @@ exports[`BpkLink should render correctly with a "alternate" attribute 1`] = `
     class="bpk-link bpk-link--alternate"
     href="#"
   >
-    Link
+    <span
+      class="bpk-link-underlined bpk-link-underlined--alternate"
+    >
+      Link
+    </span>
   </a>
 </DocumentFragment>
 `;
@@ -32,7 +40,11 @@ exports[`BpkLink should render correctly with a "blank" attribute 1`] = `
     rel="noopener noreferrer"
     target="_blank"
   >
-    Link (new window)
+    <span
+      class="bpk-link-underlined"
+    >
+      Link (new window)
+    </span>
   </a>
 </DocumentFragment>
 `;
@@ -43,7 +55,11 @@ exports[`BpkLink should render correctly with a "className" attribute 1`] = `
     class="bpk-link test-class"
     href="#"
   >
-    Link
+    <span
+      class="bpk-link-underlined"
+    >
+      Link
+    </span>
   </a>
 </DocumentFragment>
 `;
@@ -54,7 +70,11 @@ exports[`BpkLink should render correctly with a "href" attribute 1`] = `
     class="bpk-link"
     href="#"
   >
-    Link
+    <span
+      class="bpk-link-underlined"
+    >
+      Link
+    </span>
   </a>
 </DocumentFragment>
 `;
@@ -67,7 +87,11 @@ exports[`BpkLink should render correctly with a "rel" attribute 1`] = `
     rel="rel-attr"
     target="_blank"
   >
-    Link (new window)
+    <span
+      class="bpk-link-underlined"
+    >
+      Link (new window)
+    </span>
   </a>
 </DocumentFragment>
 `;
@@ -79,7 +103,11 @@ exports[`BpkLink should render correctly with arbitrary attributes 1`] = `
     href="#"
     id="test-id"
   >
-    Link
+    <span
+      class="bpk-link-underlined"
+    >
+      Link
+    </span>
   </a>
 </DocumentFragment>
 `;
diff --git a/packages/bpk-component-modal/src/__snapshots__/BpkModalInner-test.tsx.snap b/packages/bpk-component-modal/src/__snapshots__/BpkModalInner-test.tsx.snap
index 597b125354..6a268dda3e 100644
--- a/packages/bpk-component-modal/src/__snapshots__/BpkModalInner-test.tsx.snap
+++ b/packages/bpk-component-modal/src/__snapshots__/BpkModalInner-test.tsx.snap
@@ -408,9 +408,13 @@ exports[`BpkModalInner should render correctly with an accessory view 1`] = `
                 label="Close"
                 type="button"
               >
-                <div>
-                  Testing
-                </div>
+                <span
+                  class="bpk-link-underlined"
+                >
+                  <div>
+                    Testing
+                  </div>
+                </span>
               </button>
             </span>
           </span>
@@ -495,7 +499,11 @@ exports[`BpkModalInner should render correctly with closeText prop 1`] = `
             class="bpk-link"
             type="button"
           >
-            Dismiss
+            <span
+              class="bpk-link-underlined"
+            >
+              Dismiss
+            </span>
           </button>
         </div>
       </nav>
diff --git a/packages/bpk-component-navigation-bar/src/__snapshots__/BpkNavigationBarButtonLink-test.tsx.snap b/packages/bpk-component-navigation-bar/src/__snapshots__/BpkNavigationBarButtonLink-test.tsx.snap
index 31d1ef73b0..933c363c5f 100644
--- a/packages/bpk-component-navigation-bar/src/__snapshots__/BpkNavigationBarButtonLink-test.tsx.snap
+++ b/packages/bpk-component-navigation-bar/src/__snapshots__/BpkNavigationBarButtonLink-test.tsx.snap
@@ -9,7 +9,11 @@ exports[`BpkNavigationButtonLink should render correctly 1`] = `
       class="bpk-link"
       type="button"
     >
-      Test
+      <span
+        class="bpk-link-underlined"
+      >
+        Test
+      </span>
     </button>
   </span>
 </DocumentFragment>
diff --git a/packages/bpk-component-rtl-toggle/src/__snapshots__/BpkRtlToggle-test.tsx.snap b/packages/bpk-component-rtl-toggle/src/__snapshots__/BpkRtlToggle-test.tsx.snap
index 753c75213f..3ae6119858 100644
--- a/packages/bpk-component-rtl-toggle/src/__snapshots__/BpkRtlToggle-test.tsx.snap
+++ b/packages/bpk-component-rtl-toggle/src/__snapshots__/BpkRtlToggle-test.tsx.snap
@@ -7,7 +7,11 @@ exports[`BpkRtlToggle should render correctly 1`] = `
     title="Keyboard Shortcut: ctrl + cmd + r"
     type="button"
   >
-    RTL on
+    <span
+      class="bpk-link-underlined"
+    >
+      RTL on
+    </span>
   </button>
 </DocumentFragment>
 `;
diff --git a/packages/bpk-mixins/_typography.scss b/packages/bpk-mixins/_typography.scss
index 31a6bf8083..331e0da854 100644
--- a/packages/bpk-mixins/_typography.scss
+++ b/packages/bpk-mixins/_typography.scss
@@ -774,6 +774,77 @@
   margin-bottom: bpk-spacing-sm();
 }
 
+/// Underlined part inside an inline link.
+///
+/// @example scss
+///   .selector {
+///     @include bpk-link-underlined();
+///   }
+
+@mixin bpk-link-underlined {
+  padding-bottom: 0.03em;
+  transition: background-size 200ms ease;
+  background: linear-gradient($bpk-text-primary-day, $bpk-text-primary-day);
+  background-repeat: no-repeat;
+  background-position: 0 100%;
+  background-size: 100% $bpk-border-size-sm;
+
+  @include bpk-hover {
+    background-size: 0 $bpk-border-size-sm;
+  }
+}
+
+/// Underlined part inside an implicit inline link.
+///
+/// @example scss
+///   .selector {
+///     @include bpk-link-underlined--implicit();
+///   }
+
+@mixin bpk-link-underlined--implicit {
+  background-size: 0 $bpk-border-size-sm;
+
+  @include bpk-hover {
+    background-size: 100% $bpk-border-size-sm;
+  }
+}
+
+/// Underlined part inside an alternate inline link.
+///
+/// @example scss
+///   .selector {
+///     @include bpk-link-underlined--alternate();
+///   }
+
+@mixin bpk-link-underlined--alternate {
+  background: linear-gradient($bpk-text-on-dark-day, $bpk-text-on-dark-day);
+  background-repeat: no-repeat;
+  background-position: 0 100%;
+  background-size: 100% $bpk-border-size-sm;
+
+  @include bpk-hover {
+    background-size: 0 $bpk-border-size-sm;
+  }
+}
+
+/// Underlined part inside an implicit alternate inline link.
+///
+/// @example scss
+///   .selector {
+///     @include bpk-link-underlined-implicit--alternate();
+///   }
+
+@mixin bpk-link-underlined-implicit--alternate {
+  background: linear-gradient($bpk-text-on-dark-day, $bpk-text-on-dark-day);
+  background-repeat: no-repeat;
+  background-position: 0 100%;
+  background-size: 0 $bpk-border-size-sm;
+
+  @include bpk-hover {
+    background-size: 100% $bpk-border-size-sm;
+  }
+}
+
 /// Inline link.
 ///
 /// @example scss
@@ -783,7 +854,7 @@
 
 @mixin bpk-link {
   position: relative;
-  display: inline-block;
+  display: inline;
   padding: 0;
   border: 0;
   background-color: transparent;
@@ -805,10 +876,6 @@
       --bpk-link-hover-color,
       $bpk-text-primary-day
     );
-
-    &::after {
-      width: 0%;
-    }
   }
 
   &:visited {
@@ -825,34 +892,6 @@
       --bpk-link-active-color,
       $bpk-text-primary-day
     );
-
-    &::after {
-      width: 0%;
-    }
-  }
-
-  &::after {
-    position: absolute;
-    bottom: 0;
-    content: '';
-    display: block;
-    width: 100%;
-    height: $bpk-border-size-sm;
-    transition:
-      width 0.2s ease 0s,
-      left 0.2s ease 0s;
-
-    @include bpk-themeable-property(
-      background,
-      --bpk-link-color,
-      $bpk-text-primary-day
-    );
-
-    @media (prefers-reduced-motion) {
-      transition:
-        width 0s ease 0s,
-        left 0s ease 0s;
-    }
   }
 }
 
@@ -877,17 +916,6 @@
       --bpk-link-hover-color,
       $bpk-text-primary-day
     );
-
-    &::after {
-      width: 100%;
-    }
-  }
-
-  &::after {
-    width: 0;
-    transition:
-      width 0.2s ease 0s,
-      left 0.2s ease 0s;
   }
 
   &:active {
@@ -898,10 +926,6 @@
       --bpk-link-active-color,
       $bpk-text-primary-day
     );
-
-    &::after {
-      width: 100%;
-    }
   }
 }
 
@@ -930,14 +954,6 @@
     );
   }
 
-  &::after {
-    @include bpk-themeable-property(
-      background,
-      --bpk-link-alternate-color,
-      $bpk-text-on-dark-day
-    );
-  }
-
   &:visited {
     @include bpk-themeable-property(
       color,
@@ -955,6 +971,16 @@
   }
 }
 
+/// White link. Modifies the bpk-link mixin.
+///
+/// @require {mixin} bpk-link
+///
+/// @example scss
+///   .selector {
+///     @include bpk-link();
+///     @include bpk-link--white();
+///   }
+
 @mixin bpk-link--white {
   @include bpk-link--alternate;
 }


Reviews:
user: login: gc-skyscanner
body: <img width="269" alt="image" src="https://github.com/user-attachments/assets/33ca7ec9-bc25-4da5-bd21-892409b4bd9e" />

Seems the spacing between the text and the underline is smaller than the previous one, could you help to check if it matches the design spec?
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T06:10:36Z
user: login: gc-skyscanner
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T06:24:30Z
user: login: isteven-shu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T15:07:18Z
user: login: gc-skyscanner
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T05:25:23Z
user: login: gc-skyscanner
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T06:38:01Z

Review comments:
diff_hunk: @@ -774,6 +774,48 @@
   margin-bottom: bpk-spacing-sm();
 }
 
+@mixin bpk-link-underlined {
+  transition: background-size 200ms ease;
+  background: linear-gradient($bpk-text-primary-day, $bpk-text-primary-day);
+  background-repeat: no-repeat;
+  background-position: 0 100%;
+  background-size: 100% 0.1em;
path: packages/bpk-mixins/_typography.scss
user: login: gc-skyscanner
body: why we use 0.1em here but it is 1px($bpk-border-size-sm)before https://github.com/Skyscanner/backpack/pull/3818/files#diff-8b68398c71a79d402e4d5772bb9e41ab2abebfb66f22b9fc55145e5f02f4fde4L840

And, we should use `rem` here https://github.com/Skyscanner/backpack/blob/main/decisions/sizing-in-rem.md#decision
created_at: 2025-05-07T05:57:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,17 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
path: examples/bpk-storybook-utils/src/__snapshots__/BpkDarkExampleWrapper-test.js.snap
user: login: gc-skyscanner
body: Why do we remove it?
created_at: 2025-05-07T06:24:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -774,6 +774,48 @@
   margin-bottom: bpk-spacing-sm();
 }
 
+@mixin bpk-link-underlined {
+  transition: background-size 200ms ease;
+  background: linear-gradient($bpk-text-primary-day, $bpk-text-primary-day);
+  background-repeat: no-repeat;
+  background-position: 0 100%;
+  background-size: 100% 0.1em;
path: packages/bpk-mixins/_typography.scss
user: login: isteven-shu
body: Confirmed with designer. Use 1px as height and set a dynamic offset for the underline.
created_at: 2025-05-07T15:07:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -774,6 +774,77 @@
   margin-bottom: bpk-spacing-sm();
 }
 
+/// Underlined part inside an inline link.
+///
+/// @example scss
+///   .selector {
+///     @include bpk-link-underlined();
+///   }
+
+@mixin bpk-link-underlined {
+  padding-bottom: 0.03em;
path: packages/bpk-mixins/_typography.scss
user: login: gc-skyscanner
body: Should it be 0.22em?
```suggestion
  padding-bottom: calc(0.22em);
```
created_at: 2025-05-08T06:38:01Z
author_association: CONTRIBUTOR

PR comments:
user: login: skyscanner-backpack-bot[bot]
created_at: 2025-05-06T15:39:55Z
body: Visit https://backpack.github.io/storybook-prs/3818 to see this build running in a browser.
author_association: NONE
user: login: skyscanner-backpack-bot[bot]
created_at: 2025-05-06T15:59:15Z
body: Visit https://backpack.github.io/storybook-prs/3818 to see this build running in a browser.
author_association: NONE
user: login: skyscanner-backpack-bot[bot]
created_at: 2025-05-06T16:01:30Z
body: 
<!--
  0 failure: 
  0 warning: 
  
  1 markdown notices
  DangerID: danger-id-Danger;
-->




  ## Browser support

  If this is a visual change, make sure you've tested it in multiple browsers.
  
<p align="right">
  Generated by :no_entry_sign: <a href="https://danger.systems/js">dangerJS</a> against 7679b3659550709a3ffe55da9ec51905a7f8a207
</p>

author_association: NONE
user: login: skyscanner-backpack-bot[bot]
created_at: 2025-05-07T15:12:12Z
body: Visit https://backpack.github.io/storybook-prs/3818 to see this build running in a browser.
author_association: NONE
user: login: skyscanner-backpack-bot[bot]
created_at: 2025-05-07T15:21:11Z
body: Visit https://backpack.github.io/storybook-prs/3818 to see this build running in a browser.
author_association: NONE
user: login: skyscanner-backpack-bot[bot]
created_at: 2025-05-07T15:35:42Z
body: Visit https://backpack.github.io/storybook-prs/3818 to see this build running in a browser.
author_association: NONE