Europa Component Library

Contextual Navigations

Why and how to use this component

Users need a way to navigate and explore the context of the information on the current page.

When to use this component

Context navigation is placed:

  • near the top of the page, below the title. It is placed there in case the context is crucial to interpret the page content.
  • near the bottom of the page. That way it serves as a next step, for example as a next step to other content within the same context.
{#
  - "label" (string): label displayed before the list (default: '')
  - "items" (array): [{
    "href" (string): target of the link (default: '#')
    "label" (string): label of the link (default: '')
  }]
  - "limit" (integer): max number of items to display (0 = display all) (default: 5)
  - "more_label": label of the "see more items" button (default: "More")
  - "extra_classes" (string): extra CSS classes to be added
  - "extra_attributes" (array): extra attributes classes (optional, format: [{ 'name': 'name_of_the_attribute', 'value': 'value_of_the_attribute'}])
#}

{% set label = label|default('') %}
{% set limit = limit|default(4) %}
{% set more_label = more_label|default('More') %}

{# Internal properties #}

{% set _css_class = 'ecl-context-nav' %}
{% set _extra_attributes = '' %}

{# Internal logic - Process properties #}

{% if extra_class is defined %}
  {% set _css_class = _css_class ~ ' ' ~ extra_Class %}
{% endif %}

{% if extra_attributes is defined %}
  {% for attr in extra_attributes %}
    {% set _extra_attributes = _extra_attributes ~ ' ' ~ attr.name ~ '="' ~ attr.value ~'"' %}
  {% endfor %}
{% endif %}

{# Print the result  #}

<div class="{{ _css_class }}" {{ _extra_attributes|raw }}>
  <span class="ecl-context-nav__label">{{ label }}</span>
  {% if items is defined and items is iterable %}
  <ul class="ecl-context-nav__list">
    {% for item in items %}
    <li class="ecl-context-nav__item{{ limit > 0 and loop.index > limit ? ' ecl-context-nav__item--over-limit' : '' }}">
      {% include '@ec-europa/ecl-links' with {
        'variant': 'standalone',
        }|merge(item)
      %}
    </li>
    {% endfor %}

    {% if items|length > limit %}
    <li class="ecl-context-nav__item ecl-context-nav__more">
      {% include '@ec-europa/ecl-buttons' with {
        'modifier': 'none',
        'label': more_label,
        'extra_classes': 'ecl-context-nav__button ecl-link ecl-link--standalone',
        'icon': 'caret-right'
      } %}
    </li>
    {% endif %}
  </ul>
  {% endif %}
</div>
{
  "_demo": {
    "scripts": "document.addEventListener('DOMContentLoaded', function () { ECL.contextualNavs(); });"
  },
  "label": "Label for contextual nav",
  "items": [
    {
      "href": "#",
      "label": "Item one"
    },
    {
      "href": "#",
      "label": "Item two"
    },
    {
      "href": "#",
      "label": "Item three"
    },
    {
      "href": "#",
      "label": "Item four"
    },
    {
      "href": "#",
      "label": "Item five"
    },
    {
      "href": "#",
      "label": "Item six"
    },
    {
      "href": "#",
      "label": "Item seven"
    }
  ]
}
<div class="ecl-context-nav">
  <span class="ecl-context-nav__label">Label for contextual nav</span>
  <ul class="ecl-context-nav__list">
    <li class="ecl-context-nav__item">

      <a class="ecl-link ecl-link--standalone" href="#">Item one</a>
    </li>
    <li class="ecl-context-nav__item">

      <a class="ecl-link ecl-link--standalone" href="#">Item two</a>
    </li>
    <li class="ecl-context-nav__item">

      <a class="ecl-link ecl-link--standalone" href="#">Item three</a>
    </li>
    <li class="ecl-context-nav__item">

      <a class="ecl-link ecl-link--standalone" href="#">Item four</a>
    </li>
    <li class="ecl-context-nav__item ecl-context-nav__item--over-limit">

      <a class="ecl-link ecl-link--standalone" href="#">Item five</a>
    </li>
    <li class="ecl-context-nav__item ecl-context-nav__item--over-limit">

      <a class="ecl-link ecl-link--standalone" href="#">Item six</a>
    </li>
    <li class="ecl-context-nav__item ecl-context-nav__item--over-limit">

      <a class="ecl-link ecl-link--standalone" href="#">Item seven</a>
    </li>

    <li class="ecl-context-nav__item ecl-context-nav__more">

      <button class="ecl-button ecl-button--none ecl-button--caret-right ecl-context-nav__button ecl-link ecl-link--standalone">More</button>
    </li>
  </ul>
</div>
  • Content:
    /**
     * Contextual navigation scripts
     */
    
    import { queryAll } from '@ec-europa/ecl-base/helpers/dom';
    
    const expandContextualNav = (
      contextualNav,
      button,
      {
        classToRemove = 'ecl-context-nav__item--over-limit',
        hiddenElementsSelector = '.ecl-context-nav__item--over-limit',
        context = document,
      } = {}
    ) => {
      if (!contextualNav) {
        return;
      }
    
      const hiddenElements = queryAll(hiddenElementsSelector, context);
    
      // Remove extra class
      hiddenElements.forEach(element => {
        element.classList.remove(classToRemove);
      });
    
      // Remove buttton
      button.parentNode.removeChild(button);
    };
    
    // Helper method to automatically attach the event listener to all the expandables on page load
    export const contextualNavs = ({
      selector = '.ecl-context-nav',
      buttonSelector = '.ecl-context-nav__more',
      hiddenElementsSelector = '.ecl-context-nav__item--over-limit',
      classToRemove = 'ecl-context-nav__item--over-limit',
      context = document,
    } = {}) => {
      const nodesArray = queryAll(selector, context);
    
      nodesArray.forEach(node => {
        const button = context.querySelector(buttonSelector);
    
        if (button) {
          button.addEventListener('click', () =>
            expandContextualNav(node, button, {
              classToRemove,
              hiddenElementsSelector,
            })
          );
        }
      });
    };
    
    export default contextualNavs;
    
  • URL: /components/raw/ecl-context-navs/ecl-context-navs.js
  • Filesystem Path: framework/components/ecl-context-navs/ecl-context-navs.js
  • Size: 1.4 KB
  • Content:
    /*
     * Contextual navigation
     * @define context-nav
     */
    
    .ecl-context-nav {
      display: flex;
      flex-direction: column;
      font-size: map-get($ecl-font-size, 'xs');
      margin: 0;
    }
    
    .ecl-context-nav__label {
      margin-bottom: map-get($ecl-spacing, 'xxxs');
    }
    
    .ecl-context-nav__list {
      list-style: none;
      margin: 0;
      padding: 0;
    }
    
    .ecl-context-nav__item {
      display: inline-block;
    
      &::after {
        color: map-get($ecl-colors, 'grey-50');
        content: '|';
        margin-left: map-get($ecl-spacing, 'xxxs');
        margin-right: map-get($ecl-spacing, 'xxxs');
      }
    }
    
    .ecl-context-nav__item:last-child {
      &::after {
        display: none;
        margin-left: 0;
        margin-right: 0;
      }
    }
    
    .ecl-context-nav__button {
      border-width: 0;
      font-size: map-get($ecl-font-size, 'xs');
      font-weight: normal;
      padding: 0;
    
      &:focus {
        outline-offset: 0;
      }
    }
    
    .ecl-context-nav__item--over-limit {
      display: none;
    }
    
    .no-js {
      .ecl-context-nav__item--over-limit {
        display: inline-block;
      }
    
      .ecl-context-nav__more {
        display: none;
      }
    }
    
    @include ecl-media-breakpoint-up(md) {
      .ecl-context-nav {
        flex-direction: row;
      }
    
      .ecl-context-nav__label {
        flex: 0 0 25%;
        margin-bottom: 0;
      }
    }
    
  • URL: /components/raw/ecl-context-navs/ecl-context-navs.scss
  • Filesystem Path: framework/components/ecl-context-navs/ecl-context-navs.scss
  • Size: 1.2 KB
  • Handle: @ec-europa/ecl-context-navs
  • Tags: atom
  • Preview:
  • Filesystem Path: framework/components/ecl-context-navs/ecl-context-navs.twig