Inpage navigations
Why and how to use this component
Inpage navigation gives the user an overview of page contents.\ It provides in-page (or anchor) links to all H2 headings on that page. It helps users to orient themselves on the page and allows them to jump directly to content that is lower on the page, without scrolling first through the rest of the page content. A page with in-page links to content also makes it easier to refer to that specific content when shared.
When to use this component
- on pages with extensive body text that is clearly structured
- left column, always at the top of the page
- note that the page’s first columns are reserved for the in-page navigation
Do not use this component
- when the content is above the fold (the part of the page visible without scrolling)
Implementation
Inpage navigation relies on expandable component, and two javascript libraries.
Also, following script has to be added to your page:
document.addEventListener('DOMContentLoaded', function() {
ECL.initExpandables();
ECL.navigationInpages();
});
{#
- title: string; title of the navigation block (default: '')
- links: array;
{
href: string; target of the anchor, with a "#". should be an existing id in the page (default: '')
label: string; label of the anchor (default: '')
}
#}
{# Internal properties #}
{% set _cssClass = 'ecl-navigation-inpage' %}
{% set _extraAttributes = '' %}
{# Internal logic - Process properties #}
{% if extraClass is defined %}
{% set _cssClass = _cssClass ~ ' ' ~ extraClass %}
{% endif %}
{% if extraAttributes is defined %}
{% for attr in extraAttributes %}
{% set _extraAttributes = _extraAttributes ~ ' ' ~ attr.name ~ '="' ~ attr.value ~'"' %}
{% endfor %}
{% endif %}
{# Print the result #}
<nav class="{{ _cssClass }}" {{ _extraAttributes }}>
<div class="ecl-navigation-inpage__title">{{ title }}</div>
<div class="ecl-navigation-inpage__body">
<div class="ecl-navigation-inpage__trigger" aria-controls="ecl-navigation-inpage-list" aria-expanded="false" id="ecl-navigation-inpage-trigger"> </div>
<ul class="ecl-navigation-inpage__list" aria-hidden="true" aria-labelledby="ecl-navigation-inpage-trigger" id="ecl-navigation-inpage-list">
{% for link in links %}
<li class="ecl-navigation-inpage__item">
{% include '@ec-europa/ecl-links' with {
'extra_classes': 'ecl-navigation-inpage__link',
'variant': 'standalone',
}|merge(link)
%}
</li>
{% endfor %}
</ul>
</div>
</nav>
{
"title": "Page content",
"links": [
{
"href": "#inline-nav-1",
"label": "Heading 1"
},
{
"href": "#inline-nav-2",
"label": "Heading 2"
},
{
"href": "#inline-nav-3",
"label": "Heading 3"
}
],
"_demo": {
"scripts": "document.addEventListener('DOMContentLoaded', function () { ECL.initExpandables(); ECL.navigationInpages(); });"
}
}
<nav class="ecl-navigation-inpage">
<div class="ecl-navigation-inpage__title">Page content</div>
<div class="ecl-navigation-inpage__body">
<div class="ecl-navigation-inpage__trigger" aria-controls="ecl-navigation-inpage-list" aria-expanded="false" id="ecl-navigation-inpage-trigger"> </div>
<ul class="ecl-navigation-inpage__list" aria-hidden="true" aria-labelledby="ecl-navigation-inpage-trigger" id="ecl-navigation-inpage-list">
<li class="ecl-navigation-inpage__item">
<a class="ecl-link ecl-link--standalone ecl-navigation-inpage__link" href="#inline-nav-1">Heading 1</a>
</li>
<li class="ecl-navigation-inpage__item">
<a class="ecl-link ecl-link--standalone ecl-navigation-inpage__link" href="#inline-nav-2">Heading 2</a>
</li>
<li class="ecl-navigation-inpage__item">
<a class="ecl-link ecl-link--standalone ecl-navigation-inpage__link" href="#inline-nav-3">Heading 3</a>
</li>
</ul>
</div>
</nav>
-
Content:
/** * Navigation inpage related behaviors. */ import stickybits from 'stickybits'; import gumshoe from 'gumshoejs'; /** * @param {object} options Object containing configuration overrides */ export const navigationInpages = ({ stickySelector: stickySelector = '.ecl-navigation-inpage', spySelector: spySelector = '.ecl-navigation-inpage__link', spyClass: spyClass = 'ecl-navigation-inpage__link--is-active', spyTrigger: spyTrigger = '.ecl-navigation-inpage__trigger', spyOffset: spyOffset = 20, } = {}) => { // SUPPORTS if ( !('querySelector' in document) || !('addEventListener' in window) || !document.documentElement.classList ) return null; // ACTIONS function initSticky() { // init sticky menu // eslint-disable-next-line no-undef stickybits(stickySelector, { useStickyClasses: true }); } function initScrollSpy() { // init scrollspy // eslint-disable-next-line no-undef gumshoe.init({ selector: spySelector, activeClass: spyClass, offset: spyOffset, callback(nav) { // eslint-disable-line if (!nav) return; const navigationTitle = document.querySelector(spyTrigger); navigationTitle.innerHTML = nav.nav.innerHTML; }, }); } // INIT function init() { initSticky(); initScrollSpy(); } init(); // REVEAL API return { init, }; }; // module exports export default navigationInpages;
- URL: /components/raw/ecl-navigation-inpages/ecl-navigation-inpages.js
- Filesystem Path: framework/components/ecl-navigation/ecl-navigation-inpages/ecl-navigation-inpages.js
- Size: 1.5 KB
-
Content:
/** * ECL Navigation inpage * @define navigation-inpage */ .ecl-navigation-inpage { margin: 0; z-index: map-get($ecl-z-index, 'navigation'); } .ecl-navigation-inpage__trigger { color: #fff; display: none; padding: map-get($ecl-spacing, 'xxs'); position: relative; &::after { @extend %ecl-icon--after; @include ecl-icon('arrow-down'); align-items: center; background-color: map-get($ecl-colors, 'blue-110'); display: flex; font-size: map-get($ecl-font-size, 'xxxs'); height: 100%; justify-content: center; position: absolute; right: 0; top: 0; width: map-get($ecl-spacing, 'l'); } } .ecl-navigation-inpage__title { color: map-get($ecl-colors, 'grey-75'); display: none; padding-bottom: map-get($ecl-spacing, 'xs'); padding-top: map-get($ecl-spacing, 'xxs'); text-transform: uppercase; } .ecl-navigation-inpage__list { list-style-type: none; margin: 0; padding: 0; } @include ecl-media-breakpoint-down(sm) { /* stylelint-disable plugin/selector-bem-pattern */ .ecl-navigation-inpage.js-is-sticky, .ecl-navigation-inpage.js-is-stuck { .ecl-navigation-inpage__body { background-color: $ecl-color-primary; left: 0; position: fixed; right: 0; top: 0; } .ecl-navigation-inpage__link { border-top: 1px solid map-get($ecl-colors, 'blue-110'); color: #fff; display: block; padding: map-get($ecl-spacing, 'xxxs') map-get($ecl-spacing, 'xxs'); text-decoration: underline; } .ecl-navigation-inpage__trigger { display: block; } } /* stylelint-enable */ } @include ecl-media-breakpoint-up(md) { /* stylelint-disable plugin/selector-bem-pattern */ .ecl-navigation-inpage__title { display: block; } .ecl-navigation-inpage__list[aria-hidden] { display: block; } .ecl-navigation-inpage__link { border-left: 3px solid transparent; color: $ecl-color-shade; display: block; font-weight: 600; padding: map-get($ecl-spacing, 'xxxs'); &:hover { text-decoration: underline; } &:focus { background-color: map-get($ecl-colors, 'yellow-100'); outline: none; text-decoration: underline; } } .ecl-navigation-inpage__link--is-active { background-color: map-get($ecl-colors, 'grey-10'); border-left-color: $ecl-color-primary; } /* stylelint-enable */ }
- URL: /components/raw/ecl-navigation-inpages/ecl-navigation-inpages.scss
- Filesystem Path: framework/components/ecl-navigation/ecl-navigation-inpages/ecl-navigation-inpages.scss
- Size: 2.4 KB
- Handle: @ec-europa/ecl-navigation-inpages
- Tags: molecule
- Preview:
- Filesystem Path: framework/components/ecl-navigation/ecl-navigation-inpages/ecl-navigation-inpages.twig