Repository: mi6/ic-ui-kit
Pull request #3414: Skip link fixes
Author: login: GCHQ-Developer-112
Created: 2025-04-08T16:37:29Z | Merged: 2025-04-15T15:11:20Z

<!-- 🙏 Thank you for your contribution, it is greatly appreciated! -->

## Summary of the changes

- Add layout/placement styling for inline variant of skip link
- Add position top CSS prop
- Prefix hashtag in IcSkipLink's target prop
- Add example of nested skip link in IcTreeView to Storybook
- Update IcSkipLink's Inline stories in Storybook
- Update tests and stories following the new prefixing in the `target` prop

## Checklist

### General 

- [x] Changes to docs package checked and committed.
- [x] All acceptance criteria reviewed and met. 

### Testing

- [x] Relevant unit tests and visual regression tests added. 
- [x] Visual testing against Figma component specification completed. 
- [x] Playground stories in React Storybook up to date, with any prop changes and additions addressed. 

### Accessibility 

- [x] Accessibility Insights FastPass performed.
- [x] A11y unit test added and yields no issues.
- [ ] A11y plug-in on Storybook yields no issues. 
- [x] Manual screen reader testing performed using NVDA and VoiceOver. 
- [x] Manual keyboard testing for keyboard controls and logical focus order. 
- [x] Correct roles used and ARIA attributes used correctly where required. 
- [x] Logical heading structure is maintained, and the HTML elements used for headings can be changed to fit within the wider page structure. 


### Testing content extremes

- [x] All prop combinations work without issue. 
- [x] Props/slots can be updated after initial render.


Diff:
diff --git a/packages/canary-react/src/stories/ic-tree-view.stories.js b/packages/canary-react/src/stories/ic-tree-view.stories.js
index 26d2e3cf3e3..595ac5fc40d 100644
--- a/packages/canary-react/src/stories/ic-tree-view.stories.js
+++ b/packages/canary-react/src/stories/ic-tree-view.stories.js
@@ -1,6 +1,6 @@
 /* eslint-disable react/jsx-no-bind */
 /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
-import { IcButton, IcTypography, SlottedSVG } from "@ukic/react";
+import { IcButton, IcTypography, IcSkipLink, SlottedSVG } from "@ukic/react";
 import React, { useState } from "react";
 import treeItemReadme from "../../../canary-web-components/src/components/ic-tree-item/readme.md";
 import readme from "../../../canary-web-components/src/components/ic-tree-view/readme.md";
@@ -848,6 +848,29 @@ export const UpdatingOptionsSlotted = {
   name: "Updating options - slotted",
 };
 
+export const WithNestedSkipLink = {
+  render: () => {
+    <div style={{ width: "250px" }}>
+      <IcSkipLink target="next-content" inline />
+      <IcTreeView heading="Menu">
+        <IcTreeItem label="Coffee">
+          <IcTreeItem label="Americano">
+            <IcTreeItem label="With milk" />
+          </IcTreeItem>
+          <IcTreeItem label="Latte" />
+          <IcTreeItem label="Espresso" />
+        </IcTreeItem>
+        <IcTreeItem label="Tea">
+          <IcTreeItem label="Earl Grey" />
+          <IcTreeItem label="Chai" />
+        </IcTreeItem>
+        <IcTreeItem label="Hot chocolate" />
+      </IcTreeView>
+    </div>
+  },
+  name: "Nested skip link",
+};
+
 const defaultArgs = {
   heading: "Menu",
   size: "medium",
diff --git a/packages/canary-web-components/src/components/ic-tree-view/ic-tree-view.stories.js b/packages/canary-web-components/src/components/ic-tree-view/ic-tree-view.stories.js
index e8f82de69c0..8f7d8d5aa74 100644
--- a/packages/canary-web-components/src/components/ic-tree-view/ic-tree-view.stories.js
+++ b/packages/canary-web-components/src/components/ic-tree-view/ic-tree-view.stories.js
@@ -807,3 +807,26 @@ export const FocusInsetSlotted = {
   `,
   name: "Focus inset - slotted",
 };
+
+export const WithNestedSkipLink = {
+  render: () => html`
+    <div style="width:250px">
+      <ic-skip-link target="next-content" inline="true"></ic-skip-link>
+      <ic-tree-view heading="Menu">
+        <ic-tree-item label="Coffee">
+          <ic-tree-item label="Americano">
+            <ic-tree-item label="With milk"></ic-tree-item>
+          </ic-tree-item>
+          <ic-tree-item label="Latte"></ic-tree-item>
+          <ic-tree-item label="Espresso"></ic-tree-item>
+        </ic-tree-item>
+        <ic-tree-item label="Tea">
+          <ic-tree-item label="Earl Grey"></ic-tree-item>
+          <ic-tree-item label="Chai"></ic-tree-item>
+        </ic-tree-item>
+        <ic-tree-item label="Hot chocolate"></ic-tree-item>
+      </ic-tree-view>
+    </div>
+  `,
+  name: "Nested skip link",
+};
diff --git a/packages/docs/docs.json b/packages/docs/docs.json
index de0fb25d4f2..33bdd3e4c38 100644
--- a/packages/docs/docs.json
+++ b/packages/docs/docs.json
@@ -16240,7 +16240,7 @@
           "mutable": false,
           "attr": "full-width",
           "reflectToAttr": false,
-          "docs": "If `true`, the link will fill the width of the page.",
+          "docs": "If `true`, the skip link will fill the width of the page.",
           "docsTags": [],
           "default": "false",
           "values": [
@@ -16264,7 +16264,7 @@
           "mutable": false,
           "attr": "inline",
           "reflectToAttr": false,
-          "docs": "If `true`, the link will appear inline with surrounding page content when focused.",
+          "docs": "If `true`, the skip link will appear inline with surrounding page content when focused.",
           "docsTags": [],
           "default": "false",
           "values": [
@@ -16288,7 +16288,7 @@
           "mutable": false,
           "attr": "label",
           "reflectToAttr": false,
-          "docs": "The label displayed when the link is focused.",
+          "docs": "The label displayed when the skip link is focused.",
           "docsTags": [],
           "default": "\"Skip to main content\"",
           "values": [
@@ -16312,7 +16312,7 @@
           "mutable": false,
           "attr": "monochrome",
           "reflectToAttr": false,
-          "docs": "If `true`, the link will display as black in the light theme, and white in the dark theme.",
+          "docs": "If `true`, the skip link will display as black in the light theme, and white in the dark theme.",
           "docsTags": [],
           "default": "false",
           "values": [
@@ -16415,7 +16415,13 @@
       "methods": [],
       "events": [],
       "listeners": [],
-      "styles": [],
+      "styles": [
+        {
+          "name": "--ic-skip-link-position-top",
+          "annotation": "prop",
+          "docs": "The top position of the skip link when it is not displayed inline and has an absolute position."
+        }
+      ],
       "slots": [],
       "parts": [],
       "dependents": [],
diff --git a/packages/react/cypress-image-diff-screenshots/baseline/IcSkipLink.cy.tsx/full-width.png b/packages/react/cypress-image-diff-screenshots/baseline/IcSkipLink.cy.tsx/full-width.png
index a17142debfb..c3402da737d 100755
Binary files a/packages/react/cypress-image-diff-screenshots/baseline/IcSkipLink.cy.tsx/full-width.png and b/packages/react/cypress-image-diff-screenshots/baseline/IcSkipLink.cy.tsx/full-width.png differ
diff --git a/packages/react/cypress-image-diff-screenshots/baseline/IcSkipLink.cy.tsx/inline.png b/packages/react/cypress-image-diff-screenshots/baseline/IcSkipLink.cy.tsx/inline.png
index 3dba7700775..d89462bf6e8 100755
Binary files a/packages/react/cypress-image-diff-screenshots/baseline/IcSkipLink.cy.tsx/inline.png and b/packages/react/cypress-image-diff-screenshots/baseline/IcSkipLink.cy.tsx/inline.png differ
diff --git a/packages/react/src/component-tests/IcSkipLink/IcSkipLink.cy.tsx b/packages/react/src/component-tests/IcSkipLink/IcSkipLink.cy.tsx
index 670ecc8614a..157aec90816 100644
--- a/packages/react/src/component-tests/IcSkipLink/IcSkipLink.cy.tsx
+++ b/packages/react/src/component-tests/IcSkipLink/IcSkipLink.cy.tsx
@@ -3,7 +3,12 @@
 import { mount } from "cypress/react";
 import React from "react";
 import { setThresholdBasedOnEnv } from "../../../cypress/utils/helpers";
-import { IcButton, IcSkipLink, IcTopNavigation } from "../../components";
+import {
+  IcButton,
+  IcSkipLink,
+  IcTopNavigation,
+  IcTypography,
+} from "../../components";
 import { SlottedSVG } from "../../react-component-lib/slottedSVG";
 import { HAVE_FOCUS } from "../utils/constants";
 
@@ -23,7 +28,7 @@ describe("IcSkipLink e2e, visual regression and a11y tests", () => {
   it("should render IcSkipLink", () => {
     mount(
       <>
-        <IcSkipLink target="#page-content" />
+        <IcSkipLink target="page-content" />
         <a id="page-content" tabIndex={-1}>
           {" "}
         </a>
@@ -47,7 +52,7 @@ describe("IcSkipLink e2e, visual regression and a11y tests", () => {
   it("should render IcSkipLink with a custom label", () => {
     mount(
       <>
-        <IcSkipLink target="#page-content" label="Custom skip label" />
+        <IcSkipLink target="page-content" label="Custom skip label" />
         <a id="page-content" tabIndex={-1}>
           {" "}
         </a>
@@ -76,7 +81,7 @@ describe("IcSkipLink e2e, visual regression and a11y tests", () => {
           paddingBottom: "100px",
         }}
       >
-        <IcSkipLink target="#page-content" transparentBackground />
+        <IcSkipLink target="page-content" transparentBackground />
         <a id="page-content" tabIndex={-1}>
           {" "}
         </a>
@@ -100,7 +105,7 @@ describe("IcSkipLink e2e, visual regression and a11y tests", () => {
   it("should render IcSkipLink at the full width of the page", () => {
     mount(
       <>
-        <IcSkipLink target="#page-content" fullWidth />
+        <IcSkipLink target="page-content" fullWidth />
         <a id="page-content" tabIndex={-1}>
           {" "}
         </a>
@@ -137,7 +142,11 @@ describe("IcSkipLink e2e, visual regression and a11y tests", () => {
             <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z" />
           </SlottedSVG>
         </IcTopNavigation>
-        <IcSkipLink target="#page-content" inline />
+        <IcSkipLink
+          target="page-content"
+          inline
+          style={{ marginLeft: "var(--ic-space-xs)" }}
+        />
         <a id="page-content" tabIndex={-1}>
           {" "}
         </a>
@@ -161,7 +170,7 @@ describe("IcSkipLink e2e, visual regression and a11y tests", () => {
   it("should render IcSkipLink in dark theme", () => {
     mount(
       <>
-        <IcSkipLink target="#page-content" theme="dark" />
+        <IcSkipLink target="page-content" theme="dark" />
         <a id="page-content" tabIndex={-1}>
           {" "}
         </a>
@@ -185,7 +194,7 @@ describe("IcSkipLink e2e, visual regression and a11y tests", () => {
   it("should render IcSkipLink in monochrome", () => {
     mount(
       <>
-        <IcSkipLink target="#page-content" monochrome />
+        <IcSkipLink target="page-content" monochrome />
         <a id="page-content" tabIndex={-1}>
           {" "}
         </a>
@@ -209,7 +218,7 @@ describe("IcSkipLink e2e, visual regression and a11y tests", () => {
   it("should move focus to the target element when the link is clicked", () => {
     mount(
       <>
-        <IcSkipLink target="#page-content" />
+        <IcSkipLink target="page-content" />
         <main id="page-content">Target element</main>
         <IcButton>Should receive next focus</IcButton>
       </>
@@ -245,7 +254,7 @@ describe("IcSkipLink visual regression high-contrast", () => {
   it("should render IcSkipLink with a custom label", () => {
     mount(
       <>
-        <IcSkipLink target="#page-content" label="Custom skip label" />
+        <IcSkipLink target="page-content" label="Custom skip label" />
         <a id="page-content" tabIndex={-1}>
           {" "}
         </a>
diff --git a/packages/react/src/stories/ic-skip-link.stories.js b/packages/react/src/stories/ic-skip-link.stories.js
index 33f14f6b8c3..41947a35cac 100644
--- a/packages/react/src/stories/ic-skip-link.stories.js
+++ b/packages/react/src/stories/ic-skip-link.stories.js
@@ -1,6 +1,20 @@
 /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
-import React from "react";
-import { IcButton, IcSkipLink, IcTopNavigation } from "../components";
+import React, { useEffect, useRef } from "react";
+import {
+  IcButton,
+  IcSkipLink,
+  IcTopNavigation,
+  IcNavigationButton,
+  IcNavigationItem,
+  IcSearchBar,
+  IcNavigationGroup,
+  IcSectionContainer,
+  IcTypography,
+  IcCheckboxGroup,
+  IcCheckbox,
+  IcFooter,
+  IcLink,
+} from "../components";
 import { SlottedSVG } from "../react-component-lib/slottedSVG";
 
 export default {
@@ -11,8 +25,8 @@ export default {
 export const Default = {
   render: () => (
     <>
-      <IcSkipLink target="#page-content" />
-      <IcTopNavigation app-title="Application Name">
+      <IcSkipLink target="page-content" />
+      <IcTopNavigation appTitle="Application Name">
         <SlottedSVG
           slot="app-icon"
           xmlns="http://www.w3.org/2000/svg"
@@ -37,8 +51,8 @@ export const Default = {
 export const FullWidth = {
   render: () => (
     <>
-      <IcSkipLink target="#page-content" fullWidth />
-      <IcTopNavigation app-title="Application Name">
+      <IcSkipLink target="page-content" fullWidth />
+      <IcTopNavigation appTitle="Application Name">
         <SlottedSVG
           slot="app-icon"
           xmlns="http://www.w3.org/2000/svg"
@@ -60,45 +74,403 @@ export const FullWidth = {
   name: "Full width",
 };
 
+export const CustomTopPosition = {
+  render: () => {
+    const cookieBannerRef = useRef();
+    const skipLinkRef = useRef();
+    const debounce = (func, delay) => {
+      let timeout;
+      return (...args) => {
+        clearTimeout(timeout);
+        timeout = setTimeout(() => func(...args), delay);
+      };
+    };
+    const updateSkipLinkPosition = () => {
+      const cookieBanner = cookieBannerRef?.current;
+      const skipLink = skipLinkRef?.current;
+      if (cookieBanner && skipLink) {
+        requestAnimationFrame(() => {
+          const bannerHeight = cookieBanner.offsetHeight;
+          console.log({bannerHeight})
+          skipLink.style.setProperty("--ic-skip-link-position-top", `${bannerHeight + 12}px`);
+        });
+      }
+    };
+    const observeHydration = () => {
+      const cookieBanner = cookieBannerRef?.current;
+      const sectionContainer = cookieBanner?.querySelector("ic-section-container");
+      if (sectionContainer) {
+        const observer = new MutationObserver((mutationsList) => {
+          for (const mutation of mutationsList) {
+            if (
+              mutation.type === "attributes" &&
+              mutation.attributeName === "class" &&
+              sectionContainer.classList.contains("hydrated")
+            ) {
+              updateSkipLinkPosition(cookieBannerRef, skipLinkRef);
+              observer.disconnect();
+            }
+          }
+        });
+        observer.observe(sectionContainer, { attributes: true });
+      }
+    };
+    const useSkipLinkPosition = () => {
+      useEffect(() => {
+        observeHydration(cookieBannerRef, skipLinkRef);
+        const debouncedResize = debounce(() => updateSkipLinkPosition(cookieBannerRef, skipLinkRef), 100);
+        window.addEventListener("resize", debouncedResize);
+        updateSkipLinkPosition(cookieBannerRef, skipLinkRef);
+        return () => {
+          window.removeEventListener("resize", debouncedResize);
+        };
+      }, [cookieBannerRef, skipLinkRef]);
+    };
+    const closeCookieBanner = () => {
+      const cookieBanner = cookieBannerRef?.current;
+      console.log(cookieBanner)
+      if (cookieBannerRef?.current) {
+        cookieBannerRef.current.style.setProperty("display", "none");
+        updateSkipLinkPosition(cookieBannerRef, skipLinkRef);
+      }
+    };
+    useSkipLinkPosition();
+    return (
+      <div style={{ display: "flex", flexDirection: "column", minHeight: "100vh" }}>
+        <div
+          id="cookie-banner"
+          aria-label="cookies banner"
+          role="region"
+          ref={cookieBannerRef}
+          style={{
+            background: "var(--ic-architectural-60)",
+            boxShadow: "var(--ic-elevation-modal)",
+            zIndex: "var(--ic-z-index-classification-banner)",
+            position: "sticky",
+            top: "0",
+            width: "100%",
+            padding: "var(--ic-space-md) 0" }}
+        >
+          <IcSectionContainer fullHeight aligned="full-width">
+            <IcTypography variant="h2">
+              Cookies and Storage on this site
+            </IcTypography>
+            <IcTypography variant="body">
+              We’d like to use analytics cookies to understand how you use the
+              Design System, so that we can make improvements. Additionally, we
+              use local storage to improve your experience by remembering your
+              preferences.
+            </IcTypography>
+            <div
+              className="buttons"
+              style={{
+                display: "grid",
+                columnGap: "var(--ic-space-md)",
+                gridTemplateColumns: "auto auto auto",
+                justifyContent: "start",
+                alignItems: "center",
+                padding: "var(--ic-space-md) 0 var(--ic-space-xs)"
+              }}
+            >
+              <IcButton onClick={closeCookieBanner}>Accept</IcButton>
+              <IcButton variant="secondary" onClick={closeCookieBanner}>
+                Decline
+              </IcButton>
+              <IcLink href="#">Manage preferences</IcLink>
+            </div>
+          </IcSectionContainer>
+        </div>
+        <IcSkipLink target="page-content" ref={skipLinkRef}></IcSkipLink>
+        <IcTopNavigation
+          appTitle="Application Name"
+          status="alpha"
+          version="v0.0.7"
+          contentAligned="center"
+        >
+          <SlottedSVG
+            slot="app-icon"
+            xmlns="http://www.w3.org/2000/svg"
+            height="24px"
+            viewBox="0 0 24 24"
+            width="24px"
+            fill="#000000"
+          >
+            <path d="M0 0h24v24H0V0z" fill="none" />
+            <path
+              d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
+            />
+          </SlottedSVG>
+          <IcSearchBar
+            slot="search"
+            placeholder="Search"
+            label="Search"
+          ></IcSearchBar>
+          <IcNavigationButton
+            label="button1"
+            slot="buttons"
+          >
+            <SlottedSVG
+              slot="icon"
+              xmlns="http://www.w3.org/2000/svg"
+              height="24px"
+              viewBox="0 0 24 24"
+              width="24px"
+              fill="#000000"
+            >
+              <path d="M0 0h24v24H0V0z" fill="none" />
+              <path
+                d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
+              />
+            </SlottedSVG>
+          </IcNavigationButton>
+          <IcNavigationItem
+            slot="navigation"
+            label="Navigation"
+            href="/"
+          ></IcNavigationItem>
+          <IcNavigationGroup
+            slot="navigation"
+            label="Navigation group"
+            expandable
+          >
+            <IcNavigationItem
+              label="Navigation"
+              href="/"
+            ></IcNavigationItem>
+            <IcNavigationItem
+              label="Navigation"
+              href="/"
+            ></IcNavigationItem>
+          </IcNavigationGroup>
+        </IcTopNavigation>
+        <main style={{ height: "100%" }}>
+          <IcSectionContainer aligned="center" id="page-content">
+            <IcTypography>
+              Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+              Vestibulum pharetra scelerisque arcu, vitae semper nisl rhoncus
+              ut. Vestibulum molestie enim at sollicitudin pellentesque. Proin
+              sit amet augue sit amet dui suscipit lobortis. Nullam at
+              consectetur ante. Suspendisse mollis ultricies porttitor. Nunc
+              laoreet leo tortor, ut tristique odio finibus a. In rutrum
+              convallis purus, vitae tristique tortor sagittis vel. Donec dictum
+              nunc a elit tristique, et facilisis est condimentum. Pellentesque
+              maximus nulla libero, nec auctor urna consequat nec. Class aptent
+              taciti sociosqu ad litora torquent per conubia nostra, per
+              inceptos himenaeos. In maximus velit a erat volutpat, sit amet
+              consequat velit rhoncus. Mauris pretium neque eget ante
+              consectetur consectetur. Morbi a consequat lectus. Donec venenatis
+              ultricies sem nec pulvinar. Fusce lacus augue, laoreet id pretium
+              id, efficitur nec leo.
+            </IcTypography>
+            <br />
+            <IcSkipLink
+              label="Skip to options"
+              target="options"
+              inline
+            ></IcSkipLink>
+            <br />
+            <IcTypography
+              >Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+              Vestibulum pharetra scelerisque arcu, vitae semper nisl rhoncus
+              ut. Vestibulum molestie enim at sollicitudin pellentesque. Proin
+              sit amet augue sit amet dui suscipit lobortis. Nullam at
+              consectetur ante. Suspendisse mollis ultricies porttitor. Nunc
+              laoreet leo tortor, ut tristique odio finibus a. In rutrum
+              convallis purus, vitae tristique tortor sagittis vel. Donec dictum
+              nunc a elit tristique, et facilisis est condimentum. Pellentesque
+              maximus nulla libero, nec auctor urna consequat nec. Class aptent
+              taciti sociosqu ad litora torquent per conubia nostra, per
+              inceptos himenaeos. In maximus velit a erat volutpat, sit amet
+              consequat velit rhoncus. Mauris pretium neque eget ante
+              consectetur consectetur. Morbi a consequat lectus. Donec venenatis
+              ultricies sem nec pulvinar. Fusce lacus augue, laoreet id pretium
+              id, efficitur nec leo.
+            </IcTypography>
+            <br />
+            <IcButton>Button</IcButton>
+            <br />
+            <br />
+            <div id="options">
+              <IcCheckboxGroup label="This is a label" required name="group1">
+                <IcCheckbox
+                  value="valueName1"
+                  label="Unselected / Default"
+                ></IcCheckbox>
+                <IcCheckbox
+                  value="valueName2"
+                  label="Selected / Default"
+                  checked
+                ></IcCheckbox>
+                <IcCheckbox
+                  value="valueName3"
+                  label="Unselected / Disabled"
+                  disabled
+                ></IcCheckbox>
+              </IcCheckboxGroup>
+            </div>
+          </IcSectionContainer>
+        </main>
+        <IcFooter
+          aligned="full-width"
+          description="The ICDS is maintained by the Design Practice Team. If you've got a question or want to feedback,
+        please get in touch."
+          caption="All content is available under the Open Government Licence v3.0, except source code and code examples which are available under the MIT Licence."
+        />
+      </div>)},
+
+  name: "Custom top position",
+  parameters: {
+    layout: "fullscreen",
+  },
+};
+
 export const Inline = {
   render: () => (
     <>
-      <IcSkipLink target="#page-content" />
-      <IcTopNavigation app-title="Application Name">
-        <SlottedSVG
-          slot="app-icon"
-          xmlns="http://www.w3.org/2000/svg"
-          height="24px"
-          viewBox="0 0 24 24"
-          width="24px"
-          fill="#000000"
-        >
-          <path d="M0 0h24v24H0V0z" fill="none" />
-          <path
-            d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
-          />
-        </SlottedSVG>
-      </IcTopNavigation>
-      <br/>
-      <br/>
-      <br/>
-      <main id="page-content">Target element</main>
-      <IcSkipLink target="#next-content" inline />
-      <br/>
-      <br/>
-      <br/>
-      <main id="next-content">Target element</main>
-      <IcButton>Should receive next focus</IcButton>
+      <IcSkipLink target="page-content" />
+      <div>
+        <div style={{display: "flex", flexDirection: "column", minHeight: "100vh"}}>
+        <IcTopNavigation appTitle="Application Name">
+          <SlottedSVG
+            slot="app-icon"
+            xmlns="http://www.w3.org/2000/svg"
+            height="24px"
+            viewBox="0 0 24 24"
+            width="24px"
+            fill="#000000"
+          >
+            <path d="M0 0h24v24H0V0z" fill="none" />
+            <path
+              d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
+            />
+          </SlottedSVG>
+          <IcSearchBar
+              slot="search"
+              placeholder="Search"
+              label="Search"
+            ></IcSearchBar>
+            <IcNavigationButton
+              label="button1"
+              slot="buttons"
+            >
+              <SlottedSVG
+                slot="icon"
+                xmlns="http://www.w3.org/2000/svg"
+                height="24px"
+                viewBox="0 0 24 24"
+                width="24px"
+                fill="#000000"
+              >
+                <path d="M0 0h24v24H0V0z" fill="none" />
+                <path
+                  d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
+                />
+              </SlottedSVG>
+            </IcNavigationButton>
+            <IcNavigationItem
+              slot="navigation"
+              label="Navigation"
+              href="/"
+            ></IcNavigationItem>
+            <IcNavigationGroup
+              slot="navigation"
+              label="Navigation group"
+              expandable
+            >
+              <IcNavigationItem
+                label="Navigation"
+                href="/"
+              ></IcNavigationItem>
+              <IcNavigationItem
+                label="Navigation"
+                href="/"
+              ></IcNavigationItem>
+            </IcNavigationGroup>
+        </IcTopNavigation>
+        <main style={{ height: "100%" }}>
+            <IcSectionContainer aligned="center" id="page-content">
+              <IcTypography>
+                Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+                Vestibulum pharetra scelerisque arcu, vitae semper nisl rhoncus
+                ut. Vestibulum molestie enim at sollicitudin pellentesque. Proin
+                sit amet augue sit amet dui suscipit lobortis. Nullam at
+                consectetur ante. Suspendisse mollis ultricies porttitor. Nunc
+                laoreet leo tortor, ut tristique odio finibus a. In rutrum
+                convallis purus, vitae tristique tortor sagittis vel. Donec dictum
+                nunc a elit tristique, et facilisis est condimentum. Pellentesque
+                maximus nulla libero, nec auctor urna consequat nec. Class aptent
+                taciti sociosqu ad litora torquent per conubia nostra, per
+                inceptos himenaeos. In maximus velit a erat volutpat, sit amet
+                consequat velit rhoncus. Mauris pretium neque eget ante
+                consectetur consectetur. Morbi a consequat lectus. Donec venenatis
+                ultricies sem nec pulvinar. Fusce lacus augue, laoreet id pretium
+                id, efficitur nec leo.
+              </IcTypography>
+              <br />
+              <IcSkipLink label="Skip to options" target="options" inline />
+              <br />
+              <IcTypography>
+                Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+                Vestibulum pharetra scelerisque arcu, vitae semper nisl rhoncus
+                ut. Vestibulum molestie enim at sollicitudin pellentesque. Proin
+                sit amet augue sit amet dui suscipit lobortis. Nullam at
+                consectetur ante. Suspendisse mollis ultricies porttitor. Nunc
+                laoreet leo tortor, ut tristique odio finibus a. In rutrum
+                convallis purus, vitae tristique tortor sagittis vel. Donec dictum
+                nunc a elit tristique, et facilisis est condimentum. Pellentesque
+                maximus nulla libero, nec auctor urna consequat nec. Class aptent
+                taciti sociosqu ad litora torquent per conubia nostra, per
+                inceptos himenaeos. In maximus velit a erat volutpat, sit amet
+                consequat velit rhoncus. Mauris pretium neque eget ante
+                consectetur consectetur. Morbi a consequat lectus. Donec venenatis
+                ultricies sem nec pulvinar. Fusce lacus augue, laoreet id pretium
+                id, efficitur nec leo.
+              </IcTypography>
+              <br />
+              <IcButton>Button</IcButton>
+              <br />
+              <br />
+              <div id="options">
+              <IcCheckboxGroup label="This is a label" required name="group1">
+                  <IcCheckbox
+                    value="valueName1"
+                    label="Unselected / Default"
+                  ></IcCheckbox>
+                  <IcCheckbox
+                    value="valueName2"
+                    label="Selected / Default"
+                    checked
+                  ></IcCheckbox>
+                  <IcCheckbox
+                    value="valueName3"
+                    label="Unselected / Disabled"
+                    disabled
+                  ></IcCheckbox>
+                </IcCheckboxGroup>
+              </div>
+            </IcSectionContainer>
+          </main>
+        </div>
+        <IcFooter
+          aligned="full-width"
+          description="The ICDS is maintained by the Design Practice Team. If you've got a question or want to feedback,
+            please get in touch."
+          caption="All content is available under the Open Government Licence v3.0, except source code and code examples which are available under the MIT Licence."
+        />
+      </div>
     </>
   ),
   name: "Inline",
+  parameters: {
+    layout: "fullscreen",
+  },
 };
 
 export const HideBackground = {
   render: () => (
     <>
-      <IcSkipLink target="#page-content" transparentBackground />
-      <IcTopNavigation app-title="Application Name">
+      <IcSkipLink target="page-content" transparentBackground />
+      <IcTopNavigation appTitle="Application Name">
         <SlottedSVG
           slot="app-icon"
           xmlns="http://www.w3.org/2000/svg"
@@ -125,7 +497,7 @@ const defaultArgs = {
   inline: false,
   label: "Skip to main content",
   monochrome: false,
-  target: "#",
+  target: "",
   theme: "inherit",
   transparentBackground: false,
 };
@@ -133,7 +505,7 @@ const defaultArgs = {
 export const Playground = {
   render: (args) => (
     <>
-      <IcSkipLink 
+      <IcSkipLink
         fullWidth={args.fullWidth}
         inline={args.inline}
         label={args.label}
@@ -142,7 +514,7 @@ export const Playground = {
         theme={args.theme}
         transparentBackground={args.transparentBackground}
       />
-      <IcTopNavigation app-title="Application Name">
+      <IcTopNavigation appTitle="Application Name">
         <SlottedSVG
           slot="app-icon"
           xmlns="http://www.w3.org/2000/svg"
@@ -157,7 +529,7 @@ export const Playground = {
           />
         </SlottedSVG>
       </IcTopNavigation>
-      <main id={args.target.replace("#", "")}>Target element</main>
+      <main id={args.target}>Target element</main>
       <IcButton>Should receive next focus</IcButton>
     </>
   ),
diff --git a/packages/web-components/src/components.d.ts b/packages/web-components/src/components.d.ts
index ef4be6b1291..1e4564dcd80 100644
--- a/packages/web-components/src/components.d.ts
+++ b/packages/web-components/src/components.d.ts
@@ -1855,19 +1855,19 @@ export namespace Components {
     }
     interface IcSkipLink {
         /**
-          * If `true`, the link will fill the width of the page.
+          * If `true`, the skip link will fill the width of the page.
          */
         "fullWidth": boolean;
         /**
-          * If `true`, the link will appear inline with surrounding page content when focused.
+          * If `true`, the skip link will appear inline with surrounding page content when focused.
          */
         "inline": boolean;
         /**
-          * The label displayed when the link is focused.
+          * The label displayed when the skip link is focused.
          */
         "label": string;
         /**
-          * If `true`, the link will display as black in the light theme, and white in the dark theme.
+          * If `true`, the skip link will display as black in the light theme, and white in the dark theme.
          */
         "monochrome": boolean;
         /**
@@ -5355,19 +5355,19 @@ declare namespace LocalJSX {
     }
     interface IcSkipLink {
         /**
-          * If `true`, the link will fill the width of the page.
+          * If `true`, the skip link will fill the width of the page.
          */
         "fullWidth"?: boolean;
         /**
-          * If `true`, the link will appear inline with surrounding page content when focused.
+          * If `true`, the skip link will appear inline with surrounding page content when focused.
          */
         "inline"?: boolean;
         /**
-          * The label displayed when the link is focused.
+          * The label displayed when the skip link is focused.
          */
         "label"?: string;
         /**
-          * If `true`, the link will display as black in the light theme, and white in the dark theme.
+          * If `true`, the skip link will display as black in the light theme, and white in the dark theme.
          */
         "monochrome"?: boolean;
         /**
diff --git a/packages/web-components/src/components/ic-skip-link/ic-skip-link.css b/packages/web-components/src/components/ic-skip-link/ic-skip-link.css
index d2cb1d7ad2e..e26d839ac8a 100644
--- a/packages/web-components/src/components/ic-skip-link/ic-skip-link.css
+++ b/packages/web-components/src/components/ic-skip-link/ic-skip-link.css
@@ -1,3 +1,11 @@
+/**
+* @prop --ic-skip-link-position-top: The top position of the skip link when it is not displayed inline and has an absolute position.
+*/
+
+:host {
+  display: block;
+}
+
 ic-link {
   position: absolute;
   left: -9999px;
@@ -9,16 +17,27 @@ ic-link:focus {
   padding: var(--ic-space-sm);
   box-shadow: var(--ic-border-focus);
   border-radius: var(--ic-border-radius);
+  width: fit-content;
 }
 
 .display-top:focus {
-  top: var(--ic-space-sm);
+  top: var(--ic-skip-link-position-top, var(--ic-space-sm));
+}
+
+.inline:focus {
+  position: static;
+  display: inline-block;
+  margin: var(--ic-space-xs) 0;
 }
 
 .full-width:focus {
   display: flex;
-  justify-content: center;
   right: var(--ic-space-sm);
+  width: auto;
+}
+
+.inline.full-width:focus {
+  justify-content: start;
 }
 
 .show-background {
diff --git a/packages/web-components/src/components/ic-skip-link/ic-skip-link.stories.js b/packages/web-components/src/components/ic-skip-link/ic-skip-link.stories.js
index 7647a0f0523..30124ebe48b 100644
--- a/packages/web-components/src/components/ic-skip-link/ic-skip-link.stories.js
+++ b/packages/web-components/src/components/ic-skip-link/ic-skip-link.stories.js
@@ -7,7 +7,7 @@ export default {
 
 export const Default = {
   render: () =>
-    html`<ic-skip-link target="#page-content"></ic-skip-link>
+    html`<ic-skip-link target="page-content"></ic-skip-link>
       <ic-top-navigation app-title="Application Name">
         <svg
           slot="app-icon"
@@ -30,7 +30,7 @@ export const Default = {
 
 export const FullWidth = {
   render: () =>
-    html`<ic-skip-link target="#page-content" full-width="true"></ic-skip-link>
+    html`<ic-skip-link target="page-content" full-width="true"></ic-skip-link>
       <ic-top-navigation app-title="Application Name">
         <svg
           slot="app-icon"
@@ -51,41 +51,385 @@ export const FullWidth = {
   name: "Full width",
 };
 
-export const Inline = {
+export const CustomTopPosition = {
   render: () =>
-    html`<ic-skip-link target="#page-content"></ic-skip-link>
-      <ic-top-navigation app-title="Application Name">
-        <svg
-          slot="app-icon"
-          xmlns="http://www.w3.org/2000/svg"
-          height="24px"
-          viewBox="0 0 24 24"
-          width="24px"
-          fill="#000000"
+    html`<div style="display: flex; flex-direction: column; min-height: 100vh;">
+        <div
+          id="cookie-banner"
+          aria-label="cookies banner"
+          role="region"
+          style="background: var(--ic-architectural-60); box-shadow: var(--ic-elevation-modal); z-index: var(--ic-z-index-classification-banner); position: sticky; top: 0; width: 100%; padding: var(--ic-space-md) 0"
         >
-          <path d="M0 0h24v24H0V0z" fill="none" />
-          <path
-            d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
-          />
-        </svg>
-      </ic-top-navigation>
-      <br />
-      <br />
-      <br />
-      <main id="page-content">Target element</main>
-      <ic-skip-link target="#next-content" inline="true"></ic-skip-link>
-      <br />
-      <br />
-      <br />
-      <main id="next-content">Next target element</main>
-      <ic-button>Should receive last focus</ic-button>`,
+          <ic-section-container full-height aligned="full-width">
+            <ic-typography variant="h2">
+              Cookies and Storage on this site
+            </ic-typography>
+            <ic-typography variant="body">
+              We’d like to use analytics cookies to understand how you use the
+              Design System, so that we can make improvements. Additionally, we
+              use local storage to improve your experience by remembering your
+              preferences.
+            </ic-typography>
+            <div
+              className="buttons"
+              style="display: grid; column-gap: var(--ic-space-md); grid-template-columns: auto auto auto; justify-content: start; align-items: center; padding: var(--ic-space-md) 0 var(--ic-space-xs);"
+            >
+              <ic-button onclick="closeCookieBanner()"> Accept </ic-button>
+              <ic-button variant="secondary" onclick="closeCookieBanner()">
+                Decline
+              </ic-button>
+              <ic-link href=""> Manage preferences </ic-link>
+            </div>
+          </ic-section-container>
+        </div>
+        <ic-skip-link target="page-content"></ic-skip-link>
+        <ic-top-navigation
+          app-title="Application Name"
+          status="alpha"
+          version="v0.0.7"
+          content-aligned="center"
+        >
+          <svg
+            slot="app-icon"
+            xmlns="http://www.w3.org/2000/svg"
+            height="24px"
+            viewBox="0 0 24 24"
+            width="24px"
+            fill="#000000"
+          >
+            <path d="M0 0h24v24H0V0z" fill="none" />
+            <path
+              d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
+            />
+          </svg>
+          <ic-search-bar
+            slot="search"
+            placeholder="Search"
+            label="Search"
+          ></ic-search-bar>
+          <ic-navigation-button
+            label="button1"
+            slot="buttons"
+            onclick="alert('test')"
+          >
+            <svg
+              slot="icon"
+              xmlns="http://www.w3.org/2000/svg"
+              height="24px"
+              viewBox="0 0 24 24"
+              width="24px"
+              fill="#000000"
+            >
+              <path d="M0 0h24v24H0V0z" fill="none" />
+              <path
+                d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
+              />
+            </svg>
+          </ic-navigation-button>
+          <ic-navigation-item
+            slot="navigation"
+            label="Navigation"
+            href="/"
+          ></ic-navigation-item>
+          <ic-navigation-group
+            slot="navigation"
+            label="Navigation group"
+            expandable="true"
+          >
+            <ic-navigation-item
+              label="Navigation"
+              href="/"
+            ></ic-navigation-item>
+            <ic-navigation-item
+              label="Navigation"
+              href="/"
+            ></ic-navigation-item>
+          </ic-navigation-group>
+        </ic-top-navigation>
+        <main style="height: 100%">
+          <ic-section-container aligned="center" id="page-content">
+            <ic-typography
+              >Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+              Vestibulum pharetra scelerisque arcu, vitae semper nisl rhoncus
+              ut. Vestibulum molestie enim at sollicitudin pellentesque. Proin
+              sit amet augue sit amet dui suscipit lobortis. Nullam at
+              consectetur ante. Suspendisse mollis ultricies porttitor. Nunc
+              laoreet leo tortor, ut tristique odio finibus a. In rutrum
+              convallis purus, vitae tristique tortor sagittis vel. Donec dictum
+              nunc a elit tristique, et facilisis est condimentum. Pellentesque
+              maximus nulla libero, nec auctor urna consequat nec. Class aptent
+              taciti sociosqu ad litora torquent per conubia nostra, per
+              inceptos himenaeos. In maximus velit a erat volutpat, sit amet
+              consequat velit rhoncus. Mauris pretium neque eget ante
+              consectetur consectetur. Morbi a consequat lectus. Donec venenatis
+              ultricies sem nec pulvinar. Fusce lacus augue, laoreet id pretium
+              id, efficitur nec leo.</ic-typography
+            >
+            <br />
+            <ic-skip-link
+              label="Skip to options"
+              target="page-content"
+              inline="true"
+            ></ic-skip-link>
+            <br />
+            <ic-typography
+              >Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+              Vestibulum pharetra scelerisque arcu, vitae semper nisl rhoncus
+              ut. Vestibulum molestie enim at sollicitudin pellentesque. Proin
+              sit amet augue sit amet dui suscipit lobortis. Nullam at
+              consectetur ante. Suspendisse mollis ultricies porttitor. Nunc
+              laoreet leo tortor, ut tristique odio finibus a. In rutrum
+              convallis purus, vitae tristique tortor sagittis vel. Donec dictum
+              nunc a elit tristique, et facilisis est condimentum. Pellentesque
+              maximus nulla libero, nec auctor urna consequat nec. Class aptent
+              taciti sociosqu ad litora torquent per conubia nostra, per
+              inceptos himenaeos. In maximus velit a erat volutpat, sit amet
+              consequat velit rhoncus. Mauris pretium neque eget ante
+              consectetur consectetur. Morbi a consequat lectus. Donec venenatis
+              ultricies sem nec pulvinar. Fusce lacus augue, laoreet id pretium
+              id, efficitur nec leo.</ic-typography
+            >
+            <div id="options">
+              <ic-checkbox-group label="This is a label" required name="group1">
+                <ic-checkbox
+                  value="valueName1"
+                  label="Unselected / Default"
+                ></ic-checkbox>
+                <ic-checkbox
+                  value="valueName2"
+                  label="Selected / Default"
+                  checked
+                ></ic-checkbox>
+                <ic-checkbox
+                  value="valueName3"
+                  label="Unselected / Disabled"
+                  Disabled
+                ></ic-checkbox>
+              </ic-checkbox-group>
+            </div>
+          </ic-section-container>
+        </main>
+        <ic-footer
+          aligned="full-width"
+          description="The ICDS is maintained by the Design Practice Team. If you've got a question or want to feedback,
+        please get in touch."
+          caption="All content is available under the Open Government Licence v3.0, except source code and code examples which are available under the MIT Licence."
+        ></ic-footer>
+      </div>
+      <script>
+        const debounce = (func, delay) => {
+          let timeout;
+          return (...args) => {
+            clearTimeout(timeout);
+            timeout = setTimeout(() => func(...args), delay);
+          };
+        };
+        const updateSkipLinkPosition = () => {
+          const cookieBanner = document.getElementById("cookie-banner");
+          const skipLink = document.querySelector("ic-skip-link");
+          if (cookieBanner && skipLink) {
+            requestAnimationFrame(() => {
+              const bannerHeight = cookieBanner.offsetHeight;
+              skipLink.style.setProperty(
+                "--ic-skip-link-position-top",
+                bannerHeight + 12 + "px"
+              );
+            });
+          }
+        };
+        const observeHydration = () => {
+          const cookieBanner = document.getElementById("cookie-banner");
+          const sectionContainer = cookieBanner?.querySelector(
+            "ic-section-container"
+          );
+          if (sectionContainer) {
+            const observer = new MutationObserver((mutationsList) => {
+              for (const mutation of mutationsList) {
+                if (
+                  mutation.type === "attributes" &&
+                  mutation.attributeName === "class" &&
+                  sectionContainer.classList.contains("hydrated")
+                ) {
+                  updateSkipLinkPosition();
+                  observer.disconnect();
+                }
+              }
+            });
+            observer.observe(sectionContainer, { attributes: true });
+          }
+        };
+        document.addEventListener("DOMContentLoaded", () => {
+          observeHydration();
+          const debouncedResize = debounce(updateSkipLinkPosition, 100);
+          window.addEventListener("resize", debouncedResize);
+        });
+        const closeCookieBanner = () => {
+          const cookieBanner = document.getElementById("cookie-banner");
+          cookieBanner.style.setProperty("display", "none");
+          updateSkipLinkPosition();
+        };
+      </script>`,
+
+  name: "Custom top position",
+  parameters: {
+    layout: "fullscreen",
+  },
+};
+
+export const Inline = {
+  render: () =>
+    html`<ic-skip-link target="page-content"></ic-skip-link>
+      <div>
+        <div style="display: flex; flex-direction: column; min-height: 100vh;">
+          <ic-top-navigation
+            app-title="Application Name"
+            status="alpha"
+            version="v0.0.7"
+            content-aligned="center"
+          >
+            <svg
+              slot="app-icon"
+              xmlns="http://www.w3.org/2000/svg"
+              height="24px"
+              viewBox="0 0 24 24"
+              width="24px"
+              fill="#000000"
+            >
+              <path d="M0 0h24v24H0V0z" fill="none" />
+              <path
+                d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
+              />
+            </svg>
+            <ic-search-bar
+              slot="search"
+              placeholder="Search"
+              label="Search"
+            ></ic-search-bar>
+            <ic-navigation-button
+              label="button1"
+              slot="buttons"
+              onclick="alert('test')"
+            >
+              <svg
+                slot="icon"
+                xmlns="http://www.w3.org/2000/svg"
+                height="24px"
+                viewBox="0 0 24 24"
+                width="24px"
+                fill="#000000"
+              >
+                <path d="M0 0h24v24H0V0z" fill="none" />
+                <path
+                  d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5.5-2.5l7.51-3.49L17.5 6.5 9.99 9.99 6.5 17.5zm5.5-6.6c.61 0 1.1.49 1.1 1.1s-.49 1.1-1.1 1.1-1.1-.49-1.1-1.1.49-1.1 1.1-1.1z"
+                />
+              </svg>
+            </ic-navigation-button>
+            <ic-navigation-item
+              slot="navigation"
+              label="Navigation"
+              href="/"
+            ></ic-navigation-item>
+            <ic-navigation-group
+              slot="navigation"
+              label="Navigation group"
+              expandable="true"
+            >
+              <ic-navigation-item
+                label="Navigation"
+                href="/"
+              ></ic-navigation-item>
+              <ic-navigation-item
+                label="Navigation"
+                href="/"
+              ></ic-navigation-item>
+            </ic-navigation-group>
+          </ic-top-navigation>
+          <main style="height: 100%">
+            <ic-section-container aligned="center" id="page-content">
+              <ic-typography
+                >Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+                Vestibulum pharetra scelerisque arcu, vitae semper nisl rhoncus
+                ut. Vestibulum molestie enim at sollicitudin pellentesque. Proin
+                sit amet augue sit amet dui suscipit lobortis. Nullam at
+                consectetur ante. Suspendisse mollis ultricies porttitor. Nunc
+                laoreet leo tortor, ut tristique odio finibus a. In rutrum
+                convallis purus, vitae tristique tortor sagittis vel. Donec
+                dictum nunc a elit tristique, et facilisis est condimentum.
+                Pellentesque maximus nulla libero, nec auctor urna consequat
+                nec. Class aptent taciti sociosqu ad litora torquent per conubia
+                nostra, per inceptos himenaeos. In maximus velit a erat
+                volutpat, sit amet consequat velit rhoncus. Mauris pretium neque
+                eget ante consectetur consectetur. Morbi a consequat lectus.
+                Donec venenatis ultricies sem nec pulvinar. Fusce lacus augue,
+                laoreet id pretium id, efficitur nec leo.</ic-typography
+              >
+              <br />
+              <ic-skip-link
+                label="Skip to options"
+                target="page-content"
+                inline="true"
+              ></ic-skip-link>
+              <br />
+              <ic-typography
+                >Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+                Vestibulum pharetra scelerisque arcu, vitae semper nisl rhoncus
+                ut. Vestibulum molestie enim at sollicitudin pellentesque. Proin
+                sit amet augue sit amet dui suscipit lobortis. Nullam at
+                consectetur ante. Suspendisse mollis ultricies porttitor. Nunc
+                laoreet leo tortor, ut tristique odio finibus a. In rutrum
+                convallis purus, vitae tristique tortor sagittis vel. Donec
+                dictum nunc a elit tristique, et facilisis est condimentum.
+                Pellentesque maximus nulla libero, nec auctor urna consequat
+                nec. Class aptent taciti sociosqu ad litora torquent per conubia
+                nostra, per inceptos himenaeos. In maximus velit a erat
+                volutpat, sit amet consequat velit rhoncus. Mauris pretium neque
+                eget ante consectetur consectetur. Morbi a consequat lectus.
+                Donec venenatis ultricies sem nec pulvinar. Fusce lacus augue,
+                laoreet id pretium id, efficitur nec leo.</ic-typography
+              >
+              <div id="options">
+                <ic-checkbox-group
+                  label="This is a label"
+                  required
+                  name="group1"
+                >
+                  <ic-checkbox
+                    value="valueName1"
+                    label="Unselected / Default"
+                  ></ic-checkbox>
+                  <ic-checkbox
+                    value="valueName2"
+                    label="Selected / Default"
+                    checked
+                  ></ic-checkbox>
+                  <ic-checkbox
+                    value="valueName3"
+                    label="Unselected / Disabled"
+                    Disabled
+                  ></ic-checkbox>
+                </ic-checkbox-group>
+              </div>
+            </ic-section-container>
+          </main>
+        </div>
+        <ic-footer
+          aligned="full-width"
+          description="The ICDS is maintained by the Design Practice Team. If you've got a question or want to feedback,
+          please get in touch."
+          caption="All content is available under the Open Government Licence v3.0, except source code and code examples which are available under the MIT Licence."
+        ></ic-footer>
+      </div>`,
+
   name: "Inline",
+  parameters: {
+    layout: "fullscreen",
+  },
 };
 
 export const HideBackground = {
   render: () =>
     html`<ic-skip-link
-        target="#page-content"
+        target="page-content"
         transparent-background="true"
       ></ic-skip-link>
       <ic-top-navigation app-title="Application Name">
@@ -113,7 +457,7 @@ const defaultArgs = {
   inline: false,
   label: "Skip to main content",
   monochrome: false,
-  target: "#",
+  target: "",
   theme: "inherit",
   transparentBackground: false,
 };
@@ -144,7 +488,7 @@ export const Playground = {
           />
         </svg>
       </ic-top-navigation>
-      <main id=${args.target.replace("#", "")}>Target element</main>
+      <main id=${args.target}>Target element</main>
       <ic-button>Should receive next focus</ic-button>`,
 
   args: defaultArgs,
diff --git a/packages/web-components/src/components/ic-skip-link/ic-skip-link.tsx b/packages/web-components/src/components/ic-skip-link/ic-skip-link.tsx
index 031e7dfcc14..191725542e8 100644
--- a/packages/web-components/src/components/ic-skip-link/ic-skip-link.tsx
+++ b/packages/web-components/src/components/ic-skip-link/ic-skip-link.tsx
@@ -10,24 +10,24 @@ export class SkipLink {
   @Element() el: HTMLIcSkipLinkElement;
 
   /**
-   * If `true`, the link will fill the width of the page.
+   * If `true`, the skip link will fill the width of the page.
    */
-  @Prop() fullWidth = false;
+  @Prop() fullWidth: boolean = false;
 
   /**
-   * If `true`, the link will appear inline with surrounding page content when focused.
+   * If `true`, the skip link will appear inline with surrounding page content when focused.
    */
-  @Prop() inline = false;
+  @Prop() inline: boolean = false;
 
   /**
-   * The label displayed when the link is focused.
+   * The label displayed when the skip link is focused.
    */
-  @Prop() label = "Skip to main content";
+  @Prop() label: string = "Skip to main content";
 
   /**
-   * If `true`, the link will display as black in the light theme, and white in the dark theme.
+   * If `true`, the skip link will display as black in the light theme, and white in the dark theme.
    */
-  @Prop() monochrome = false;
+  @Prop() monochrome: boolean = false;
 
   /**
    * The target ID for the element which should receive focus when triggering the skip link.
@@ -42,7 +42,7 @@ export class SkipLink {
   /**
    * If `true`, the background will be hidden.
    */
-  @Prop() transparentBackground = false;
+  @Prop() transparentBackground: boolean = false;
 
   render() {
     const {
@@ -64,10 +64,11 @@ export class SkipLink {
         <ic-link
           class={{
             "display-top": !inline,
-            "full-width": fullWidth,
+            "full-width": !!fullWidth,
             "show-background": !transparentBackground,
+            inline: !!inline,
           }}
-          href={target}
+          href={`#${target}`}
           monochrome={monochrome}
           theme={theme}
         >
diff --git a/packages/web-components/src/components/ic-skip-link/readme.md b/packages/web-components/src/components/ic-skip-link/readme.md
index a53fe5a96c9..dd631311381 100644
--- a/packages/web-components/src/components/ic-skip-link/readme.md
+++ b/packages/web-components/src/components/ic-skip-link/readme.md
@@ -9,15 +9,22 @@
 
 | Property                | Attribute                | Description                                                                                                                             | Type                             | Default                  |
 | ----------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------ |
-| `fullWidth`             | `full-width`             | If `true`, the link will fill the width of the page.                                                                                    | `boolean`                        | `false`                  |
-| `inline`                | `inline`                 | If `true`, the link will appear inline with surrounding page content when focused.                                                      | `boolean`                        | `false`                  |
-| `label`                 | `label`                  | The label displayed when the link is focused.                                                                                           | `string`                         | `"Skip to main content"` |
-| `monochrome`            | `monochrome`             | If `true`, the link will display as black in the light theme, and white in the dark theme.                                              | `boolean`                        | `false`                  |
+| `fullWidth`             | `full-width`             | If `true`, the skip link will fill the width of the page.                                                                               | `boolean`                        | `false`                  |
+| `inline`                | `inline`                 | If `true`, the skip link will appear inline with surrounding page content when focused.                                                 | `boolean`                        | `false`                  |
+| `label`                 | `label`                  | The label displayed when the skip link is focused.                                                                                      | `string`                         | `"Skip to main content"` |
+| `monochrome`            | `monochrome`             | If `true`, the skip link will display as black in the light theme, and white in the dark theme.                                         | `boolean`                        | `false`                  |
 | `target` _(required)_   | `target`                 | The target ID for the element which should receive focus when triggering the skip link.                                                 | `string`                         | `undefined`              |
 | `theme`                 | `theme`                  | Sets the theme color to the dark or light theme color. `inherit` will set the color based on the system settings or ic-theme component. | `"dark" \| "inherit" \| "light"` | `"inherit"`              |
 | `transparentBackground` | `transparent-background` | If `true`, the background will be hidden.                                                                                               | `boolean`                        | `false`                  |
 
 
+## CSS Custom Properties
+
+| Name                          | Description                                                                                     |
+| ----------------------------- | ----------------------------------------------------------------------------------------------- |
+| `--ic-skip-link-position-top` | The top position of the skip link when it is not displayed inline and has an absolute position. |
+
+
 ## Dependencies
 
 ### Depends on
diff --git a/packages/web-components/src/components/ic-skip-link/test/__snapshots__/ic-skip-link.spec.ts.snap b/packages/web-components/src/components/ic-skip-link/test/__snapshots__/ic-skip-link.spec.ts.snap
index 06ede0b73b8..5ed1b0d9951 100644
--- a/packages/web-components/src/components/ic-skip-link/test/__snapshots__/ic-skip-link.spec.ts.snap
+++ b/packages/web-components/src/components/ic-skip-link/test/__snapshots__/ic-skip-link.spec.ts.snap
@@ -1,7 +1,7 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`ic-skip-link component should pass down the theme and monochrome prop to the ic-link component 1`] = `
-<ic-skip-link class="ic-theme-dark" monochrome="true" target="#page-content" theme="dark">
+<ic-skip-link class="ic-theme-dark" monochrome="true" target="page-content" theme="dark">
   <template shadowrootmode="open">
     <ic-link class="display-top ic-link ic-link-monochrome ic-theme-dark show-background" exportparts="link">
       <template shadowrootmode="open">
@@ -16,7 +16,7 @@ exports[`ic-skip-link component should pass down the theme and monochrome prop t
 `;
 
 exports[`ic-skip-link component should render a skip link by default with the correct text 1`] = `
-<ic-skip-link target="#page-content">
+<ic-skip-link target="page-content">
   <template shadowrootmode="open">
     <ic-link class="display-top ic-link show-background" exportparts="link">
       <template shadowrootmode="open">
@@ -31,7 +31,7 @@ exports[`ic-skip-link component should render a skip link by default with the co
 `;
 
 exports[`ic-skip-link component should render a skip link with a custom label 1`] = `
-<ic-skip-link label="Custom skip label" target="#page-content">
+<ic-skip-link label="Custom skip label" target="page-content">
   <template shadowrootmode="open">
     <ic-link class="display-top ic-link show-background" exportparts="link">
       <template shadowrootmode="open">
@@ -46,7 +46,7 @@ exports[`ic-skip-link component should render a skip link with a custom label 1`
 `;
 
 exports[`ic-skip-link component should render a skip link without a background when \`transparentBackground\` is true 1`] = `
-<ic-skip-link target="#page-content" transparent-background="true">
+<ic-skip-link target="page-content" transparent-background="true">
   <template shadowrootmode="open">
     <ic-link class="display-top ic-link" exportparts="link">
       <template shadowrootmode="open">
@@ -61,9 +61,9 @@ exports[`ic-skip-link component should render a skip link without a background w
 `;
 
 exports[`ic-skip-link component should render with the \`inline\` prop 1`] = `
-<ic-skip-link inline="true" target="#page-content">
+<ic-skip-link inline="true" target="page-content">
   <template shadowrootmode="open">
-    <ic-link class="ic-link show-background" exportparts="link">
+    <ic-link class="ic-link inline show-background" exportparts="link">
       <template shadowrootmode="open">
         <a class="link" href="#page-content" part="link" tabindex="0">
           <slot></slot>
diff --git a/packages/web-components/src/components/ic-skip-link/test/ic-skip-link.spec.ts b/packages/web-components/src/components/ic-skip-link/test/ic-skip-link.spec.ts
index 8450ffecbc0..bc08cd8eff6 100644
--- a/packages/web-components/src/components/ic-skip-link/test/ic-skip-link.spec.ts
+++ b/packages/web-components/src/components/ic-skip-link/test/ic-skip-link.spec.ts
@@ -6,7 +6,7 @@ describe("ic-skip-link component", () => {
   it("should render a skip link by default with the correct text", async () => {
     const page = await newSpecPage({
       components: [SkipLink, Link],
-      html: `<ic-skip-link target="#page-content"></ic-skip-link>`,
+      html: `<ic-skip-link target="page-content"></ic-skip-link>`,
     });
 
     expect(page.root).toMatchSnapshot();
@@ -15,7 +15,7 @@ describe("ic-skip-link component", () => {
   it("should render a skip link with a custom label", async () => {
     const page = await newSpecPage({
       components: [SkipLink, Link],
-      html: `<ic-skip-link target="#page-content" label="Custom skip label"></ic-skip-link>`,
+      html: `<ic-skip-link target="page-content" label="Custom skip label"></ic-skip-link>`,
     });
 
     expect(page.root).toMatchSnapshot();
@@ -24,7 +24,7 @@ describe("ic-skip-link component", () => {
   it("should render a skip link without a background when `transparentBackground` is true", async () => {
     const page = await newSpecPage({
       components: [SkipLink, Link],
-      html: `<ic-skip-link target="#page-content" transparent-background="true"></ic-skip-link>`,
+      html: `<ic-skip-link target="page-content" transparent-background="true"></ic-skip-link>`,
     });
 
     expect(page.root).toMatchSnapshot();
@@ -33,7 +33,7 @@ describe("ic-skip-link component", () => {
   it("should pass down the theme and monochrome prop to the ic-link component", async () => {
     const page = await newSpecPage({
       components: [SkipLink, Link],
-      html: `<ic-skip-link target="#page-content" theme="dark" monochrome="true"></ic-skip-link>`,
+      html: `<ic-skip-link target="page-content" theme="dark" monochrome="true"></ic-skip-link>`,
     });
 
     expect(page.root).toMatchSnapshot();
@@ -42,7 +42,7 @@ describe("ic-skip-link component", () => {
   it("should render with the `inline` prop", async () => {
     const page = await newSpecPage({
       components: [SkipLink, Link],
-      html: `<ic-skip-link target="#page-content" inline="true"></ic-skip-link>`,
+      html: `<ic-skip-link target="page-content" inline="true"></ic-skip-link>`,
     });
 
     expect(page.root).toMatchSnapshot();
diff --git a/packages/web-components/src/components/ic-toast/ic-toast.tsx b/packages/web-components/src/components/ic-toast/ic-toast.tsx
index 1cb6de0b8e3..606692c7838 100644
--- a/packages/web-components/src/components/ic-toast/ic-toast.tsx
+++ b/packages/web-components/src/components/ic-toast/ic-toast.tsx
@@ -289,7 +289,7 @@ export class Toast {
     if (this.isActive(isBackwards ? firstEl : lastEl))
       return isBackwards ? lastEl : firstEl;
 
-    let currentIndex: number = 0;
+    let currentIndex = 0;
 
     return this.interactiveElements.some((el, index) => {
       if (!this.isActive(el)) return false;


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: 

Copilot reviewed 7 out of 10 changed files in this pull request and generated 2 comments.

<details>
<summary>Files not reviewed (3)</summary>

* **packages/docs/docs.json**: Language not supported
* **packages/web-components/src/components/ic-skip-link/ic-skip-link.css**: Language not supported
* **packages/web-components/src/components/ic-skip-link/test/__snapshots__/ic-skip-link.spec.ts.snap**: Language not supported
</details>



state: COMMENTED
author_association: NONE
submitted_at: 2025-04-09T13:44:52Z
user: login: GCHQ-Developer-847
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T09:34:01Z
user: login: GCHQ-Developer-847
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T10:00:14Z
user: login: GCHQ-Developer-299
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T14:05:14Z
user: login: GCHQ-Developer-847
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T15:36:27Z
user: login: GCHQ-Developer-847
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T09:58:06Z
user: login: GCHQ-Developer-299
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T13:32:20Z
user: login: GCHQ-Developer-847
body: Hopefully people are ok with me reviewing this PR - I did make updates to it but only very small ones, and have checked everything thoroughly 😄
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T15:10:53Z

Review comments:
diff_hunk: @@ -445,3 +445,26 @@ export const FocusInset = {
   `,
   name: "Focus inset",
 };
+
+export const WithNestedSkipLink = {
+  render: () => html`
+    <div style="width:250px">
+      <ic-skip-link target="#next-content" inline="true"></ic-skip-link>
path: packages/canary-web-components/src/components/ic-tree-view/ic-tree-view.stories.js
user: login: Copilot
body: Since the IcSkipLink component now automatically prefixes the target prop with '#', please remove the explicit '#' from the target value to avoid generating an incorrect href (e.g., '##next-content').
```suggestion
      <ic-skip-link target="next-content" inline="true"></ic-skip-link>
```
created_at: 2025-04-09T13:44:51Z
author_association: NONE
diff_hunk: @@ -467,6 +467,29 @@ export const UpdatingOptions = {
   name: "Updating options",
 };
 
+export const WithNestedSkipLink = {
+  render: () => {
+    <div style={{ width: "250px" }}>
+      <IcSkipLink target="#next-content" inline />
path: packages/canary-react/src/stories/ic-tree-view.stories.js
user: login: Copilot
body: To align with the updated IcSkipLink behavior, remove the '#' from the target prop so that the component can correctly prepend it, ensuring the href is formed properly.
```suggestion
      <IcSkipLink target="next-content" inline />
```
created_at: 2025-04-09T13:44:52Z
author_association: NONE
path: packages/web-components/src/components/ic-skip-link/test/__snapshots__/ic-skip-link.spec.ts.snap
user: login: GCHQ-Developer-847
body: I think it might be good to update the value of the `href` props in the unit tests so these snapshots don't have double hashes
created_at: 2025-04-14T09:34:01Z
author_association: CONTRIBUTOR
path: packages/web-components/src/components/ic-skip-link/test/__snapshots__/ic-skip-link.spec.ts.snap
user: login: GCHQ-Developer-847
body: I will sort this as @GCHQ-Developer-112 is off
created_at: 2025-04-14T10:00:14Z
author_association: CONTRIBUTOR
path: packages/react/src/stories/ic-skip-link.stories.js
user: login: GCHQ-Developer-299
body: The Custom Top Position and Inline stories don't function as expected for me in chrome (tested the react storybook)

The button doesn't seem to appear in Custom Top Position story (it might be hidden under the cookie message) and in the Inline example the Skip to Options button doesn't set focus properly on the checkboxes. 
created_at: 2025-04-14T14:05:14Z
author_association: CONTRIBUTOR
path: packages/react/src/stories/ic-skip-link.stories.js
user: login: GCHQ-Developer-847
body: I'll take a look
created_at: 2025-04-14T15:36:27Z
author_association: CONTRIBUTOR
path: packages/react/src/stories/ic-skip-link.stories.js
user: login: GCHQ-Developer-847
body: Both stories should be working now :) Also added a button above the checkboxes in each story for testing that the skip link skips over it
created_at: 2025-04-15T09:58:06Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-08T16:37:53Z
body: <!-- add-pr-comment:branch-deployment -->

View your branch deployment here: https://mi6.github.io/ic-ui-kit/branches/skip-link-fixes/web-components
View your React branch deployment here: https://mi6.github.io/ic-ui-kit/branches/skip-link-fixes/react
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-08T16:37:54Z
body: <!-- add-pr-comment:canary-branch-deployment -->

View your canary branch deployment here: https://mi6.github.io/ic-ui-kit/branches/skip-link-fixes/canary-web-components
View your canary React branch deployment here: https://mi6.github.io/ic-ui-kit/branches/skip-link-fixes/canary-react
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-08T16:57:50Z
body: <!-- add-pr-comment:image-diff -->

Cypress visual tests failed.
View the image diff here: https://github.com/mi6/ic-ui-kit/tree/gh-pages/branches/skip-link-fixes/cypress-image-diff-screenshots/diff
View the html report here: https://mi6.github.io/ic-ui-kit/branches/skip-link-fixes/cypress-image-diff-html-report/cypress-image-diff-html-report.html
author_association: CONTRIBUTOR