Europa Component Library

Timeline and Time schedule

Why and how to use this component

A timeline is a way of displaying a list of events in chronological order.

There are two variants of this component:

  • timeline
  • time schedule

When to use this component

  • timeline: for bigger time ranges
  • time schedule: more granular, for hours (used on event)
{#
  Accepts:
    - "limit" (integer): max number of items to display (0 = display all)
    - "button_label" (string): button label
    - "items" (array): array of objects containing
      - "title" (string): entry's title
      - "body" (string): entry's body text (HTML)
    - "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'}])

#}

{# Internal properties #}

{% set _css_class = 'ecl-timeline' %}
{% set _extra_attributes = '' %}
{% set _button_label = button_label|default('Show all timeline') %}

{# Internal logic - Process properties #}

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

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

<section class="{{ _css_class }}"{{ _extra_attributes|raw }}>
  <ul class="ecl-timeline__list">
    {% for item in items %}
    <li class="ecl-timeline__item{{ limit is defined and limit > 0 and loop.index > limit ? ' ecl-timeline__item--over-limit' : '' }}">
      <div class="ecl-heading ecl-heading--h4 ecl-timeline__title">{{ item.title }}</div>
      <div class="ecl-timeline__body">{{ item.body }}</div>
    </li>
    {% endfor %}
  </ul>
  {% if limit is defined and limit > 0 %}
    {% include '@ec-europa/ecl-buttons' with {
      'modifier': 'call',
      'label': _button_label,
      'extra_classes': 'ecl-timeline__button',
      'icon': 'caret-down'
    } %}
  {% endif %}
</section>
{
  "limit": 3,
  "button_label": "Show all timeline",
  "items": [
    {
      "title": "By late-2013",
      "body": "\n          <p class=\"ecl-paragraph\">\n            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.\n          </p>\n          <p class=\"ecl-paragraph\">\n            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.\n          </p>\n        "
    },
    {
      "title": "By late-2014",
      "body": "\n          <p class=\"ecl-paragraph\">\n            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.\n          </p>\n        "
    },
    {
      "title": "By late-2015",
      "body": "\n          <p class=\"ecl-paragraph\">\n            The Commission will convene the first energy infrastructure forum to discuss and find solutions to issues that are common to all regions across Europe.\n          </p>\n          <p class=\"ecl-paragraph\">\n            The Commission will convene the first energy infrastructure forum to discuss and find solutions to issues that are common to all regions across Europe.\n          </p>\n        "
    },
    {
      "title": "By late-2016",
      "body": "\n          <p class=\"ecl-paragraph\">\n            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.\n          </p>\n        "
    },
    {
      "title": "By late-2017",
      "body": "\n          <p class=\"ecl-paragraph\">\n            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.\n          </p>\n        "
    },
    {
      "title": "By late-2018",
      "body": "\n          <p class=\"ecl-paragraph\">\n            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.\n          </p>\n        "
    }
  ],
  "_demo": {
    "scripts": "\n        document.addEventListener('DOMContentLoaded', function () { ECL.timelines(); });\n        "
  }
}
<section class="ecl-timeline">
  <ul class="ecl-timeline__list">
    <li class="ecl-timeline__item">
      <div class="ecl-heading ecl-heading--h4 ecl-timeline__title">By late-2013</div>
      <div class="ecl-timeline__body">
        <p class="ecl-paragraph">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.
        </p>
        <p class="ecl-paragraph">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.
        </p>
      </div>
    </li>
    <li class="ecl-timeline__item">
      <div class="ecl-heading ecl-heading--h4 ecl-timeline__title">By late-2014</div>
      <div class="ecl-timeline__body">
        <p class="ecl-paragraph">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.
        </p>
      </div>
    </li>
    <li class="ecl-timeline__item">
      <div class="ecl-heading ecl-heading--h4 ecl-timeline__title">By late-2015</div>
      <div class="ecl-timeline__body">
        <p class="ecl-paragraph">
          The Commission will convene the first energy infrastructure forum to discuss and find solutions to issues that are common to all regions across Europe.
        </p>
        <p class="ecl-paragraph">
          The Commission will convene the first energy infrastructure forum to discuss and find solutions to issues that are common to all regions across Europe.
        </p>
      </div>
    </li>
    <li class="ecl-timeline__item ecl-timeline__item--over-limit">
      <div class="ecl-heading ecl-heading--h4 ecl-timeline__title">By late-2016</div>
      <div class="ecl-timeline__body">
        <p class="ecl-paragraph">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.
        </p>
      </div>
    </li>
    <li class="ecl-timeline__item ecl-timeline__item--over-limit">
      <div class="ecl-heading ecl-heading--h4 ecl-timeline__title">By late-2017</div>
      <div class="ecl-timeline__body">
        <p class="ecl-paragraph">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.
        </p>
      </div>
    </li>
    <li class="ecl-timeline__item ecl-timeline__item--over-limit">
      <div class="ecl-heading ecl-heading--h4 ecl-timeline__title">By late-2018</div>
      <div class="ecl-timeline__body">
        <p class="ecl-paragraph">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec tellus congue, pretium nibh eu, mattis ligula. Integer tempus varius enim ut scelerisque. Curabitur rutrum vestibulum elit ac pulvinar.
        </p>
      </div>
    </li>
  </ul>

  <button class="ecl-button ecl-button--call ecl-button--caret-down ecl-timeline__button">Show all timeline</button>
</section>
  • Content:
    /**
     * Timeline
     * @define timeline
     */
    
    $ecl-timeline-bullet-size: 14px !default;
    $ecl-timeline-border-width: 4px !default;
    
    .ecl-timeline {
      border-left: $ecl-timeline-border-width solid
        map-get($ecl-colors, 'yellow-100');
      margin: 0;
      padding: 0;
    }
    
    .ecl-timeline__list {
      list-style: none;
      margin: 0;
      padding: map-get($ecl-spacing, 'm') 0 0;
    }
    
    .ecl-timeline__item {
      margin-bottom: map-get($ecl-spacing, 'l');
    }
    
    .ecl-timeline__item:last-child {
      margin-bottom: 0;
    }
    
    .ecl-timeline__item--over-limit {
      display: none;
    
      .no-js & {
        display: list-item;
      }
    }
    
    .ecl-timeline__button {
      margin-left: map-get($ecl-spacing, 'l');
    
      .no-js & {
        display: none;
      }
    }
    
    .ecl-timeline__title {
      font-weight: bold;
      margin-bottom: map-get($ecl-spacing, 'xs');
      padding-left: map-get($ecl-spacing, 'l');
      position: relative;
    
      &::before {
        background-color: #fff;
        border: 3px solid map-get($ecl-colors, 'grey-100');
        border-radius: 50%;
        content: '';
        height: $ecl-timeline-bullet-size;
        left: -(($ecl-timeline-bullet-size + $ecl-timeline-border-width) / 2);
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        width: $ecl-timeline-bullet-size;
      }
    }
    
    .ecl-timeline__body {
      color: $ecl-color-shade;
      padding-left: map-get($ecl-spacing, 'l');
    }
    
  • URL: /components/raw/ecl-timelines/_timelines.scss
  • Filesystem Path: framework/components/ecl-timelines/_timelines.scss
  • Size: 1.3 KB
  • Content:
    /**
     * Timeline
     */
    
    const expandTimeline = (
      timeline,
      button,
      {
        classToRemove = 'ecl-timeline__item--over-limit',
        hiddenElementsSelector = '.ecl-timeline__item--over-limit',
      } = {}
    ) => {
      if (!timeline) {
        return;
      }
    
      const hiddenElements = Array.prototype.slice.call(
        timeline.querySelectorAll(hiddenElementsSelector)
      );
    
      // 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 timelines = ({
      selector = '.ecl-timeline',
      buttonSelector = '.ecl-timeline__button',
      hiddenElementsSelector = '.ecl-timeline__item--over-limit',
      classToRemove = 'ecl-timeline__item--over-limit',
      context = document,
    } = {}) => {
      const nodesArray = Array.prototype.slice.call(
        context.querySelectorAll(selector)
      );
    
      nodesArray.forEach(node => {
        const button = context.querySelector(buttonSelector);
    
        if (button) {
          button.addEventListener('click', () =>
            expandTimeline(node, button, { classToRemove, hiddenElementsSelector })
          );
        }
      });
    };
    
    export default timelines;
    
  • URL: /components/raw/ecl-timelines/timelines.js
  • Filesystem Path: framework/components/ecl-timelines/timelines.js
  • Size: 1.3 KB
  • Handle: @ec-europa/ecl-timelines
  • Tags: molecule
  • Preview:
  • Filesystem Path: framework/components/ecl-timelines/ecl-timelines.twig