Guidance

Global quicklinks provide a quick and consistent way for users to access popular or important content from across University of Leeds websites.

The “quicklinks” contents should match that of the main University of Leeds website. You should not alter or add additional links to those found on the main University of Leeds website. This helps to provide consistency of user experience as site visitors move between and return to any University of Leeds site that uses the Design System.

Developer guidance

The @uol-header-global-quicklinks component should be included as part of the @uol-header-global-masthead

{% if quicklinks.length %}
  <nav class="uol-quicklinks" aria-label="University links">
    <ul class="uol-quicklinks__list">
      {% for links_group in quicklinks %}
        <li class="uol-quicklinks__group">
          {{ links_group.title }}
          {% if links_group.links.length %}
            <ul class="uol-quicklinks__group__list">
              {% for link in links_group.links %}
                <li class="uol-quicklinks__group__item">
                  <a class="uol-quicklinks__group__link" href="{{ link.url }}">{{ link.title }}</a>
                </li>
              {% endfor %}
            </ul>
          {% endif %}
        </li>
      {% endfor %}
    </ul>
  </nav>
{% endif %}
<nav class="uol-quicklinks" aria-label="University links">
    <ul class="uol-quicklinks__list">

        <li class="uol-quicklinks__group">
            Students

            <ul class="uol-quicklinks__group__list">

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/mobile-app">Mobile App</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/minerva">Minerva</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/for-students">For Students</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="https://library.leeds.ac.uk">Library</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/it">IT</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/campus-map">Campus map</a>
                </li>

            </ul>

        </li>

        <li class="uol-quicklinks__group">
            Staff

            <ul class="uol-quicklinks__group__list">

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/staff/for-staff">For Staff</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/staff/services-a-z">Services A-Z</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/staff/staff-a-z">Staff A-Z</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/staff/faculty-a-z">Faculties A-Z</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/staff/student-education-service">Student Education Service</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/staff/hr">HR</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/staff/it">IT</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/campus-map">Campus map</a>
                </li>

            </ul>

        </li>

        <li class="uol-quicklinks__group">
            Faculties

            <ul class="uol-quicklinks__group__list">

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/faculty/arts-humanities-cultures">Faculty of Arts, Humanities and Cultures</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/faculty/biological-sciences">Faculty of Biological Sciences</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/faculty/business">Faculty of Business</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/faculty/engineering-physical-sciences">Faculty of Engineering and Physical Sciences</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/faculty/environment">Faculty of Environment</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/faculty/medicine-health">Faculty of Medicine and Health</a>
                </li>

                <li class="uol-quicklinks__group__item">
                    <a class="uol-quicklinks__group__link" href="/faculty/social-sciences">Faculty of Social Sciences</a>
                </li>

            </ul>

        </li>

    </ul>
</nav>
  • Content:
    .uol-quicklinks {
    
      .no-js & {
        display: none;
      }
    
      position: relative;
      flex-grow: 2;
    
      @include media("<uol-media-m") {
        width: calc(100% - 136px);
        background: $color-black--dark;
    
        .uol-global-masthead--quicklinks-expanded & {
          width: auto;
        }
      }
      @include media(">=uol-media-m") {
        margin-right: $spacing-5;
      }
    
      @include media(">=uol-media-l") {
        max-width: calc(100% - 400px - 20rem);
      }
    }
    
      .uol-quicklinks__list {
        list-style: none;
        margin: 0;
        padding: 0;
        display: flex;
        justify-content: flex-end;
        text-align: left;
      }
    
      .uol-quicklinks__button {
        position: relative;
        margin: 0;
        white-space: nowrap;
        background: transparent;
        color: $color-white--dark;
        font-size: 1rem;
        font-weight: 500;
        border: none;
        padding: 0.9em 0.5em;
    
        &:focus {
          outline: 2px dotted transparent;
          outline-offset: -6px;
        }
    
        @include media("<uol-media-m") {
          &[aria-expanded="true"] {
            @include font-size-responsive(1.75rem, 2.25rem, 3rem);
            @include line-height-responsive(2.25rem, 3rem, 3.5rem);
    
            display: block;
            text-align: left;
            width: 100vw;
            border-bottom: 2px solid $color-brand--bright;
            margin-top: -#{$spacing-2};
            padding: 1.312rem $spacing-7 1.312rem $spacing-4;
          }
        }
    
        &::after {
          content: "";
          position: absolute;
          bottom: 0.2em;
          left: 0.2em;
          right: calc(100% - 0.2em);
          height: 0.375rem;
          background-color: rgba($color-brand--bright, 0);
          transition: right 0.4s ease 0.1s;
    
          @include media(">=uol-media-m") {
            height: $spacing-2;
          }
    
          @media (-ms-high-contrast: active),
          (forced-colors: active) {
            background-color: WindowText;
            background-color: CanvasText;
          }
        }
    
        &:hover,
        &:focus {
    
          &::after {
            right: 0.2em;
            background-color: $color-brand--bright;
          }
        }
    
        &[aria-expanded="true"] {
          &::before {
            content: "";
            position: absolute;
            right: 0.3rem;
            bottom: 0.6rem;
            width: 0;
            height: 0;
            border: $spacing-2 solid transparent;
            border-top: none;
            border-bottom-color: $color-white;
            filter: drop-shadow(0 -0.05rem 0.05rem rgba($color-black, 0.1));
            z-index: 2;
    
            @include media("<=uol-media-m") {
              display: none;
            }
          }
        }
    
        &[aria-expanded="true"] {
          @include media("<=uol-media-m") {
            &::after {
              display: none;
            }
    
            &:focus {
              text-decoration: underline;
            }
    
            &:focus:not(:focus-visible) {
              text-decoration: none;
    
            }
    
            &:focus-visible {
              outline-color: transparent;
              text-decoration: underline;
              text-underline-offset: 4px;
              text-decoration-thickness: $spacing-2;
              text-decoration-color: $color-brand--bright;
            }
          }
        }
      }
    
        .uol-quicklinks__button__icon {
          position: relative;
          display: inline-block;
          width: 1em;
          height: 1em;
          margin-left: 0.2em;
          margin-right: -0.2em;
    
          &::before,
          &::after {
            content: "";
            display: block;
            position: absolute;
            width: 0.5em;
            height: 0.13em;
            background: $color-white--dark;
            bottom: 20%;
    
            @media (-ms-high-contrast: active) {
              background: ButtonText;
            }
          }
    
          &::before {
            left: 50%;
            transform: translateX(-76%) rotate(45deg);
          }
    
          &::after {
            right: 50%;
            transform: translateX(76%) rotate(-45deg);
          }
    
          .uol-quicklinks__group--expanded & {
    
            @include media("<uol-media-m") {
              position: absolute;
              padding: $spacing-4;
              right: $spacing-3;
              top: 33%;
              transform: translateY(-50%);
            }
    
            @include media(">=uol-media-m") {
    
            }
    
            &::before {
              transform: translateX(-76%) rotate(315deg);
            }
    
            &::after {
              transform: translateX(76%) rotate(45deg);
            }
          }
        }
    
      .uol-quicklinks__group {
        position: relative;
    
        @include media(">=uol-media-m") {
          padding-right: $spacing-5;
        }
    
        .uol-quicklinks__group--more & {
          font-weight: $font-weight-bold--sans-serif;
          padding-left: $spacing-4;
    
          @include media(">=uol-media-m") {
            width: 50%;
          }
        }
      }
    
        .uol-quicklinks__group--sibling-expanded {
    
          @include media("<uol-media-m") {
            position: absolute !important;
            clip: rect(1px, 1px, 1px, 1px);
            height: 1px;
            width: 1px;
            overflow: hidden;
            left: -9999px;
          }
        }
    
        .uol-quicklinks__group__list,
        .uol-quicklinks__more-list {
          font-size: 1.75rem;
          display: none;
          padding: $spacing-4;
          list-style: none;
          background: $color-black;
          color: $color-white;
    
          @include media(">=uol-media-m") {
            position: absolute;
            top: calc(100% - #{$spacing-3});
            right: 0;
            box-sizing: border-box;
            width: 375px;
            max-width: 100vw;
            background: $color-white;
            font-weight: $font-weight-bold--sans-serif;
            color: $color-font;
            border: 1px solid rgba($color-border--light, 0.2);
            border-radius: $spacing-3;
            padding-top: $spacing-4;
            z-index: 1;
            transform: translateX($spacing-7);
            box-shadow:
              0 15px 24px 0 rgba(10, 2, 2, 0.15),
              0 5px 10px 0 rgba(33, 33, 33, 0.5);
          }
    
          @include media(">=uol-media-l") {
            right: auto;
            left: 0;
            transform: translateX(-#{$spacing-7});
    
            &::before {
              right: auto;
              left: 3.25rem;
            }
          }
    
          .uol-quicklinks__button[aria-expanded="true"] + & {
            display: block;
          }
        }
    
          .uol-quicklinks__group__list {
    
            .uol-quicklinks__group--more & {
              margin-left: -#{$spacing-4};
            }
    
            .uol-quicklinks__more-list & {
              display: block;
    
              @include media(">=uol-media-m") {
                position: relative;
                width: auto;
                top: auto;
                left: auto;
                right: 0;
                padding-top: 0;
                padding-bottom: 0;
                transform: none;
                box-shadow: none;
                border: 0;
              }
            }
          }
    
          .uol-quicklinks__more-list {
            @include media(">=uol-media-l") {
              width: 766px;
              transform: translateX(-40%);
              padding-top: $spacing-6;
    
              .uol-quicklinks__button[aria-expanded="true"] + & {
                display: flex;
              }
            }
          }
    
          .uol-quicklinks__group__item {
            padding: 0;
    
            .uol-quicklinks__group--more & {
              padding-left: 0;
              margin-left: -#{$spacing-4};
              margin-right: -#{$spacing-4};
            }
          }
    
          .uol-quicklinks__group__link {
            position: relative;
            display: block;
            padding: $spacing-4;
            font-size: 1.125rem;
            text-decoration: none;
            border-radius: 6px;
            transition: background 0.3s ease;
    
            @include media(">=uol-media-m") {
              color: $color-font--light;
            }
    
            svg {
              position: relative;
              margin-top: -0.35em;
              top: 0.35em;
              left: 0;
              margin-left: 0.5em;
              fill: rgba($color-brand--bright, 0);
              opacity: 0;
              transition: all 0.3s ease 0.2s;
    
              @media (-ms-high-contrast: active) {
                fill: windowText;
              }
            }
    
            &:hover,
            &:focus {
              background: $color-black--dark;
              text-decoration: underline;
    
              @include media(">=uol-media-m") {
                background: $colour-warmgrey—faded;
                color: $color-font--dark;
              }
    
              svg {
                left: 0.4em;
                opacity: 1;
                fill: $color-brand--bright;
    
                @media (-ms-high-contrast: active) {
                  fill: windowText;
                }
              }
            }
          }
    
  • URL: /components/raw/uol-header-global-quicklinks/_global-quicklinks.scss
  • Filesystem Path: src/library/02-components/header-partials/global-quicklinks/_global-quicklinks.scss
  • Size: 8.2 KB
  • Content:
    const svgRightArrow = `<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" focusable="false" aria-hidden="true">
      <path d="M0 0h24v24H0z" fill="none"/>
      <path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/>
    </svg>`
    
    export const globalQuicklinks = () => {
    
      // Utility getSiblings()
      const getSiblings = (element) => {
        return Array.prototype.filter.call(element.parentNode.children, function (sibling) {
          return sibling !== element;
        });
      };
    
      // Utility isDescendant()
      const isDescendant = (el, parent) => {
        let isChild = false
    
        if (el === parent) { //is this the element itself?
          isChild = true
        }
    
        while (el = el.parentNode) {
          if (el == parent) {
            isChild = true
          }
        }
    
        return isChild
      }
    
      const groupButtons = (quicklinksContainer) => {
        // Add buttons to link group parents
    
        // const groupTitles = quicklinksContainer.querySelectorAll('.uol-quicklinks__group--title-container')
        const groups = quicklinksContainer.querySelectorAll('.uol-quicklinks__group')
    
        groups.forEach( (group) => {
          const title = group.firstChild.textContent.trim()
    
          group.firstChild.remove()
    
          const button = document.createElement('button')
          button.classList.add('uol-quicklinks__button')
          button.innerHTML = `${title}<span class="uol-quicklinks__button__icon"></span>`
          button.setAttribute('aria-expanded', 'false')
          group.prepend(button)
        })
      }
    
      const moreWrap = (quicklinksContainer) => {
          // If buttons are too wide for container wrap overflowing groups in "More"
    
          const quicklinksGroups = quicklinksContainer.querySelectorAll('.uol-quicklinks__group')
          const containerWidth = quicklinksContainer.clientWidth
    
          let groupsWidth = 0
    
          let moreStart = null
    
          let moreItems = document.createElement('li')
          moreItems.classList.add('uol-quicklinks__group')
          moreItems.classList.add('uol-quicklinks__group--more')
          moreItems.innerHTML = `
            <button class="uol-quicklinks__button uol-quicklinks__button--more" aria-expanded="false">More<span class="uol-quicklinks__button__icon"></span></button>
          `
    
          let moreItemsList = document.createElement('ul')
          moreItemsList.classList.add('uol-quicklinks__more-list')
    
          quicklinksGroups.forEach( (quicklinksGroup, i) => {
    
            const groupWidth = quicklinksGroup.offsetWidth
    
            groupsWidth += groupWidth
    
            if (groupsWidth > containerWidth) {
    
              if (!moreStart) {
                moreStart = true
                let prevGroup = quicklinksGroups[i - 1]
                let prevGroupClone = prevGroup.cloneNode(true)
                // Remove button
                const newHeadingPrev = document.createTextNode(prevGroupClone.querySelector('button').innerText)
                prevGroupClone.querySelector('button').remove()
                prevGroupClone.prepend(newHeadingPrev)
                moreItemsList.appendChild(prevGroupClone)
                prevGroup.remove()
              }
    
              const itemClone = quicklinksGroup.cloneNode(true)
              // Remove button
              const newHeading = document.createTextNode(itemClone.querySelector('button').innerText)
              itemClone.querySelector('button').remove()
              itemClone.prepend(newHeading)
              moreItemsList.appendChild(itemClone)
              quicklinksGroup.remove()
            }
    
          })
    
          if (moreStart) {
            moreItems.appendChild(moreItemsList)
            quicklinksContainer.querySelector('.uol-quicklinks__list').append(moreItems)
          }
    
      }
    
      const buttonAction = (quicklinksContainer) => {
        const buttons = quicklinksContainer.querySelectorAll('.uol-quicklinks__button')
    
        buttons.forEach( (button) => {
          button.onclick = () => {
    
            let expanded = button.getAttribute('aria-expanded') === 'true' || false
    
            const siblings = getSiblings(button.parentElement)
            const containerParent = quicklinksContainer.parentNode
    
            siblings.forEach( (sibling) => {
              sibling.classList.remove('uol-quicklinks__group--expanded')
            })
    
            button.setAttribute('aria-expanded', !expanded)
    
            if (!expanded) {
    
              button.parentNode.classList.add('uol-quicklinks__group--expanded')
    
              // Alter siblings
              siblings.forEach( (sibling) => {
                sibling.classList.add('uol-quicklinks__group--sibling-expanded')
                sibling.querySelector('button').setAttribute('aria-expanded', 'false')
              })
    
              // Alter containerParent parent to hide container's siblings
              if (containerParent.classList.contains('uol-global-masthead')) {
                containerParent.classList.add('uol-global-masthead--quicklinks-expanded')
              }
            } else {
    
              button.parentNode.classList.remove('uol-quicklinks__group--expanded')
    
              // Alter siblings
              siblings.forEach( (sibling) => {
                sibling.classList.remove('uol-quicklinks__group--sibling-expanded')
              })
    
              // Alter containerParent parent to show container's siblings
              if (containerParent.classList.contains('uol-global-masthead')) {
                containerParent.classList.remove('uol-global-masthead--quicklinks-expanded')
              }
            }
    
          }
        })
      }
    
      const focusListener = (quicklinksContainer) => {
    
        const subLists = quicklinksContainer.querySelectorAll('.uol-quicklinks__group')
        const moreList = quicklinksContainer.querySelector('.uol-quicklinks__more-list')
    
        const buttons = quicklinksContainer.querySelectorAll('.uol-quicklinks__button')
    
        subLists.forEach((subList) => {
    
          subList.addEventListener('focusout', (event) => {
    
            if (event.relatedTarget) {
    
              if ( !isDescendant(event.relatedTarget, subList) && !isDescendant(event.relatedTarget, moreList) ) {
    
                quicklinksContainer.parentNode.classList.remove('uol-global-masthead--quicklinks-expanded')
                buttons.forEach( (button) => {
                  button.parentNode.classList.remove('uol-quicklinks__group--expanded')
                  button.parentNode.classList.remove('uol-quicklinks__group--sibling-expanded')
                  button.setAttribute('aria-expanded', 'false')
                })
              }
            }
    
          })
        })
    
      }
    
      const linkArrows = (quicklinksContainer) => {
    
            const subNavItems = quicklinksContainer.querySelectorAll('.uol-quicklinks__group__link')
            // Add arrows to subnav links
            subNavItems.forEach( (item) => {
    
              // Split text to array
              const innerTextArray = item.innerText.trim().split(' ')
    
              // Wrap last word and svg in no-wrap span to avoid wrapping
              item.innerHTML = innerTextArray.slice(0, -1).join(' ') + ' <span class="no-wrap">' + innerTextArray[innerTextArray.length - 1] + '' + svgRightArrow + '</span>'
            })
      }
    
      const quicklinksContainers = document.querySelectorAll('.uol-quicklinks');
    
      quicklinksContainers.forEach( (quicklinksContainer) => {
    
        // Store original HTML
        const quicklinksContainerClone = quicklinksContainer.cloneNode(true)
    
        // Initialise
        groupButtons(quicklinksContainer)
        moreWrap(quicklinksContainer)
        buttonAction(quicklinksContainer)
        focusListener(quicklinksContainer)
        linkArrows(quicklinksContainer)
    
    
        // Reset on resize
    
        let windowWidth = false
    
        window.addEventListener('resize', () => {
    
          setTimeout(() => {
    
            // Has the width changed?
            if (!windowWidth || window.innerWidth != windowWidth) {
    
              // Reset to original HTML
              quicklinksContainer.innerHTML = quicklinksContainerClone.innerHTML
              // Rerun
              groupButtons(quicklinksContainer)
              moreWrap(quicklinksContainer)
              buttonAction(quicklinksContainer)
              focusListener(quicklinksContainer)
              linkArrows(quicklinksContainer)
    
              windowWidth = window.innerWidth
    
            }
    
          }, 100);
    
        })
    
        // Close on click outside
    
        document.addEventListener("click", (evt) => {
    
          let targetElement = evt.target; // clicked element
    
          do {
              if (targetElement == quicklinksContainer) {
                  // This is a click inside. Do nothing, just return.
                  return;
              }
              // Go up the DOM
              targetElement = targetElement.parentNode;
          } while (targetElement)
    
          // This is a click outside.
          const buttons = quicklinksContainer.querySelectorAll('.uol-quicklinks__button')
    
          quicklinksContainer.parentNode.classList.remove('uol-global-masthead--quicklinks-expanded')
          buttons.forEach( (button) => {
            button.parentNode.classList.remove('uol-quicklinks__group--expanded')
            button.parentNode.classList.remove('uol-quicklinks__group--sibling-expanded')
            button.setAttribute('aria-expanded', 'false')
          })
        })
    
        // Close on escape
    
        window.addEventListener("keydown", function(event) {
    
          if (event.key === 'Escape' || event.keyCode === 27) {
            const buttons = quicklinksContainer.querySelectorAll('.uol-quicklinks__button')
    
            quicklinksContainer.parentNode.classList.remove('uol-global-masthead--quicklinks-expanded')
            buttons.forEach( (button) => {
              button.parentNode.classList.remove('uol-quicklinks__group--expanded')
              button.parentNode.classList.remove('uol-quicklinks__group--sibling-expanded')
              button.setAttribute('aria-expanded', 'false')
            })
          }
    
        }, true);
    
      })
    
    }
    
  • URL: /components/raw/uol-header-global-quicklinks/global-quicklinks.module.js
  • Filesystem Path: src/library/02-components/header-partials/global-quicklinks/global-quicklinks.module.js
  • Size: 9.5 KB
{
  "quicklinks": [
    {
      "title": "Students",
      "links": [
        {
          "title": "Mobile App",
          "url": "/mobile-app"
        },
        {
          "title": "Minerva",
          "url": "/minerva"
        },
        {
          "title": "For Students",
          "url": "/for-students"
        },
        {
          "title": "Library",
          "url": "https://library.leeds.ac.uk"
        },
        {
          "title": "IT",
          "url": "/it"
        },
        {
          "title": "Campus map",
          "url": "/campus-map"
        }
      ]
    },
    {
      "title": "Staff",
      "links": [
        {
          "title": "For Staff",
          "url": "/staff/for-staff"
        },
        {
          "title": "Services A-Z",
          "url": "/staff/services-a-z"
        },
        {
          "title": "Staff A-Z",
          "url": "/staff/staff-a-z"
        },
        {
          "title": "Faculties A-Z",
          "url": "/staff/faculty-a-z"
        },
        {
          "title": "Student Education Service",
          "url": "/staff/student-education-service"
        },
        {
          "title": "HR",
          "url": "/staff/hr"
        },
        {
          "title": "IT",
          "url": "/staff/it"
        },
        {
          "title": "Campus map",
          "url": "/campus-map"
        }
      ]
    },
    {
      "title": "Faculties",
      "links": [
        {
          "title": "Faculty of Arts, Humanities and Cultures",
          "url": "/faculty/arts-humanities-cultures"
        },
        {
          "title": "Faculty of Biological Sciences",
          "url": "/faculty/biological-sciences"
        },
        {
          "title": "Faculty of Business",
          "url": "/faculty/business"
        },
        {
          "title": "Faculty of Engineering and Physical Sciences",
          "url": "/faculty/engineering-physical-sciences"
        },
        {
          "title": "Faculty of Environment",
          "url": "/faculty/environment"
        },
        {
          "title": "Faculty of Medicine and Health",
          "url": "/faculty/medicine-health"
        },
        {
          "title": "Faculty of Social Sciences",
          "url": "/faculty/social-sciences"
        }
      ]
    }
  ]
}