Back to Video-guidelines

CSS ComponentThe latest version of this package is: 14.1.0, Opens in new window

A basic video component that can be used in various ways and on many different types of pages.

This component provides .css, .styl, .less and .scss -files.

To be able to install this component, please refer to the Project Setup documentation.

$ npm i @ids-core/video@14.1.0

Our visual identity Let us show you our new visual identity

Table of Contents

Edit this section, Opens in new window

Usage

For html5 video

<div class="if video [is-active|is-paused]">
  <video
    muted
    title="Our visual identity"
    class="if player"
    disablePictureInPicture
    poster="https://www.dreambroker.com/channel/qtauayyk/v8ukrs97/get/poster?etag=1576140475000"
    preload="none"
  >
    <track label="English" kind="subtitles" srclang="en" src="/videos/captions/vtt/if-design-en.vtt" />
    <track label="Norsk" kind="subtitles" srclang="no" src="/videos/captions/vtt/if-design-no.vtt" />
    <track label="Dansk" kind="subtitles" srclang="dk" src="/videos/captions/vtt/if-design-dk.vtt" />
    <track label="Svenska" kind="subtitles" srclang="se" src="/videos/captions/vtt/if-design-se.vtt" />
    <track label="English" kind="captions" srclang="en" src="/videos/captions/vtt/if-design-captions.en.vtt" />
    <track label="Norsk" kind="captions" srclang="no" src="/videos/captions/vtt/if-design-captions.no.vtt" />
    <source
      data-source-type="quality"
      name="Full HD"
      label="Full HD (1080p)"
      quality="1080p"
      src="https://www.dreambroker.com/channel/qtauayyk/v8ukrs97/get/fullhd.mp4"
      type="video/mp4"
    />
    <source
      data-source-type="quality"
      name="HD"
      label="HD (720p)"
      quality="720p"
      src="https://www.dreambroker.com/channel/qtauayyk/v8ukrs97/get/hd.mp4"
      type="video/mp4"
    />
    <source
      data-source-type="quality"
      name="SD"
      label="SD (480p)"
      quality="480p"
      src="https://www.dreambroker.com/channel/qtauayyk/v8ukrs97/get/normal.mp4"
      type="video/mp4"
    />
    <source
      data-source-type="quality"
      name="Mobile"
      label="Mobile (240p)"
      quality="240p"
      src="https://www.dreambroker.com/channel/qtauayyk/v8ukrs97/get/mobile.mp4"
      type="video/mp4"
    />
    Sorry, your browser doesn't support embedded videos, but don't worry, you can
    <a href="https://www.dreambroker.com/channel/qtauayyk/v8ukrs97/get/fullhd.mp4">download it</a>
    and watch it with your favorite video player!
  </video>
  <div class="if overlay">
    <span class="if title">Our visual identity</span>
    <span class="if description">
      Let us show you our new visual identity
    </span>
    <button class="if play button secondary" type="button">
      Play
    </button>
  </div>
  <div class="if controls">
    <div class="if volume-control">
      <button type="button" class="if volume button"><span class="if description">Volume</span></button>
      <input class="if volume js-volume-control" type="range" min="0" max="100" step="1" />
    </div>
    <div class="if subtitles-control">
      <button type="button" class="if subtitles button">
        <span class="if description">Subtitles</span>
      </button>
    </div>
    <div class="if seeker-control">
      <span class="if js-seeker-time-elapsed"></span>
      <progress class="if seeker js-seeker-control" value="0" min="0" max="100"></progress>
      <span class="if js-seeker-time-remaining"></span>
    </div>
    <div class="if cc-control">
      <button type="button" class="if cc button"><span class="if description">Captions</span></button>
    </div>
    <div class="if quality-control">
      <button type="button" class="if quality button">
        <span class="if js-video-quality">HD</span><span class="if description">Quality</span>
      </button>
    </div>
  </div>
</div>

JavaScript implementation example

Note!

This is just a quick example on how to implement the video player. YMMV.

/* eslint no-console:0*/

function isChrome() {
  return navigator.userAgent.indexOf('Chrome') > -1;
}

if (isChrome()) {
  document.querySelector('html').classList.add('chrome');
}
function isMobileDevice() {
  return (
    navigator.userAgent.match(/Android/i) ||
    navigator.userAgent.match(/webOS/i) ||
    navigator.userAgent.match(/iPhone/i) ||
    navigator.userAgent.match(/iPad/i) ||
    navigator.userAgent.match(/iPod/i) ||
    navigator.userAgent.match(/BlackBerry/i) ||
    navigator.userAgent.match(/Windows Phone/i)
  );
}

function checkBandwidth() {
  if (!navigator.connection) {
    if (isMobileDevice()) return '3g';
    return '4g';
  }
  return navigator.connection.effectiveType;
}

function getQualityByBandwidth() {
  var bandwidth = checkBandwidth();
  if (bandwidth == '4g') {
    return '1080p';
  } else if (bandwidth == '3g') {
    return '480p';
  } else {
    return '240p';
  }
}

function str_pad_left(string, pad, length) {
  return (new Array(length + 1).join(pad) + string).slice(-length);
}

const createMediaTimestamp = time => {
  var minutes = Math.floor(time / 60);
  var seconds = time - minutes * 60;

  var finalTime = str_pad_left(minutes, '0', 2) + ':' + str_pad_left(seconds, '0', 2);

  return finalTime;
};

const initVideo = (video, videoIndex) => {
  let pauseTime = 0;
  const videoContainer = video.parentElement;
  const videoOverlay = videoContainer.querySelector('.if.overlay');
  const playButton = videoContainer.querySelector('.if.play.button');
  const controls = videoContainer.querySelector('.if.controls');
  const captionsControl = videoContainer.querySelector('.if.cc-control');
  const captionsButton = videoContainer.querySelector('.if.cc.button');
  const qualityControl = videoContainer.querySelector('.if.quality-control');
  const qualityButton = videoContainer.querySelector('.if.quality.button');
  const subtitlesControl = videoContainer.querySelector('.if.subtitles-control');
  const subtitlesButton = videoContainer.querySelector('.if.subtitles.button');
  const seekerRange = videoContainer.querySelector('.if.js-seeker-control');
  const volumeControl = videoContainer.querySelector('.if.volume-control');
  const volumeButton = videoContainer.querySelector('.if.volume.button');
  const volumeRange = videoContainer.querySelector('.if.js-volume-control');
  const seekerElapsed = videoContainer.querySelector('.if.js-seeker-time-elapsed');
  const seekerRemaining = videoContainer.querySelector('.if.js-seeker-time-remaining');

  const titleElement = videoOverlay.querySelector('.if.title');
  const title = `video-${videoIndex}-title`;
  titleElement.setAttribute('id', title);

  video.setAttribute('aria-labelledby', title);

  const createTranscript = caption => {
    const transcriptExpandableElement = videoContainer.parentElement.querySelector('.if.panel');
    if (!transcriptExpandableElement) return;

    const transcriptExpandableTitleElement = transcriptExpandableElement.querySelector('.if.title');
    const transcriptionExpandableContentElement = transcriptExpandableElement.querySelector('.if.title + .if.content');

    const transcriptionExpandableContentId = `video-${videoIndex}-transcription-content-title`;
    const transcriptExpandableTitleId = `video-${videoIndex}-transcription-expandable-title`;

    transcriptExpandableTitleElement.setAttribute('aria-controls', transcriptionExpandableContentId);
    transcriptExpandableTitleElement.setAttribute('tabindex', 0);
    transcriptExpandableTitleElement.setAttribute('aria-expanded', 'false');
    transcriptExpandableTitleElement.setAttribute('id', transcriptExpandableTitleId);

    transcriptionExpandableContentElement.setAttribute('aria-live', 'off');
    transcriptionExpandableContentElement.setAttribute('aria-atomic', true);
    transcriptionExpandableContentElement.setAttribute('role', 'region');
    transcriptionExpandableContentElement.setAttribute('aria-relevant', 'all');
    transcriptionExpandableContentElement.setAttribute('tabindex', 0);

    Array.prototype.slice.call(caption.cues).forEach(cue => {
      var pF = document.createDocumentFragment();
      var cueLine = document.createElement('span');
      var text = document.createTextNode(cue.text);
      cueLine.appendChild(text);
      cueLine.classList.add('if');
      cueLine.classList.add('transcript-line');
      pF.appendChild(cueLine);
      transcriptionExpandableContentElement.appendChild(pF);
    });

    video.setAttribute('aria-describedby', transcriptionExpandableContentId);
  };

  if (volumeControl) {
    volumeControl.addEventListener('mouseenter', e => {
      e.target.classList.add('is-active');
    });

    if (video.muted || video.muted == 'true') {
      volumeButton.classList.add('is-muted');
    } else {
      volumeButton.classList.remove('is-muted');
    }

    volumeButton.addEventListener('click', () => {
      if (video.muted || video.muted == 'true') {
        video.muted = false;
        volumeButton.classList.remove('is-muted');
      } else {
        video.muted = true;
        volumeButton.classList.add('is-muted');
      }
    });

    volumeRange.addEventListener('change', e => {
      video.volume = e.target.value / 100;
      if (e.target.value == 0) {
        video.muted = true;
        volumeButton.classList.add('is-muted');
      } else {
        video.muted = false;
        volumeButton.classList.remove('is-muted');
      }
    });

    volumeRange.addEventListener('input', e => {
      video.volume = e.target.value / 100;
      if (isChrome()) {
        volumeRange.style.backgroundImage =
          'linear-gradient(to right, #faf9f7 0%, #faf9f7 ' +
          e.target.value +
          '%, #6e625e ' +
          e.target.value +
          '%, #6e625e 100%)';
      }
    });
  }

  if (videoOverlay && volumeControl) {
    videoOverlay.addEventListener('mouseleave', () => {
      volumeControl.classList.remove('is-active');
    });
  }

  for (var i = 0; i < video.textTracks.length; i++) {
    video.textTracks[i].mode = 'hidden';
  }

  var qualitySources = video.querySelectorAll('source[data-source-type]');

  if (!qualitySources || qualitySources.length == 0) {
    if (qualityControl) {
      qualityControl.classList.add('hidden');
    }
  } else {
    if (!qualityControl) return;
    var qualityMenuButtons = [];
    var createQualityMenuItem = function(id, name, quality, label) {
      var listItem = document.createElement('li');
      listItem.classList.add('if');
      if (label === 'separator') {
        listItem.classList.add('separator');
      }
      if (label !== 'separator') {
        var button = listItem.appendChild(document.createElement('button'));
        button.setAttribute('id', `if-video-${videoIndex}-${id}`);
        button.className = 'if';
        if (quality.length > 0) button.setAttribute('quality', quality);

        button.setAttribute('data-state', 'inactive');
        if (id === 'quality-automatic') {
          button.setAttribute('data-state', 'active');
          button.classList.add('is-active');
          var autoQuality = getQualityByBandwidth();
          button.setAttribute('quality', autoQuality);
          button.value = autoQuality;
          button.appendChild(document.createTextNode(`${name} (${autoQuality})`));
          const source = video.querySelector(`source[quality="${autoQuality}"]`);

          if (source) {
            source.remove(); //Remove the source from select
            video.prepend(source); //Prepend source on top of options
            video.load();
            controls.querySelector('.js-video-quality').textContent = source.getAttribute('name');
          }
        } else {
          button.value = quality;
          button.appendChild(document.createTextNode(label));
        }

        button.addEventListener('click', function() {
          var autoQuality = getQualityByBandwidth();
          var source;
          // Set all buttons to inactive
          qualityMenuButtons.map(button => {
            button.setAttribute('data-state', 'inactive');
            button.classList.remove('is-active');
          });
          if (id === 'quality-automatic') {
            source = video.querySelector(`source[quality="${autoQuality}"]`);
            button.textContent = `${name} (${autoQuality})`;
            controls.querySelector('.js-video-quality').textContent = source.getAttribute('name');
          } else {
            source = video.querySelector(`source[quality="${quality}"]`);
            controls.querySelector('.js-video-quality').textContent = name;
          }

          pauseTime = video.currentTime; //Get Current Time of Video
          source.remove(); //Remove the source from select
          video.prepend(source); //Prepend source on top of options
          video.load(); //Reload Video
          video.play(); //Resume video
          video.currentTime = pauseTime; //Continue from video's stop

          button.setAttribute('data-state', 'active');
          button.classList.add('is-active');

          qualityMenuHolder.classList.toggle('is-open');
          qualityMenu.classList.toggle('is-open');
        });
        qualityMenuButtons.push(button);
      }
      return listItem;
    };
    var qualityMenu;
    var qualityMenuHolder;
    if (qualitySources.length && qualitySources.length > 1) {
      var df = document.createDocumentFragment();
      qualityMenuHolder = df.appendChild(document.createElement('div'));
      qualityMenuHolder.classList.add('if');
      qualityMenuHolder.classList.add('dropdown-menu');
      qualityMenuHolder.classList.add('bottom');
      qualityMenuHolder.classList.add('left');
      qualityMenu = qualityMenuHolder.appendChild(document.createElement('ul'));
      qualityMenu.className = 'if';

      qualitySources.forEach(source => {
        qualityMenu.appendChild(
          createQualityMenuItem(
            'quality-' + source.getAttribute('quality'),
            source.getAttribute('name'),
            source.getAttribute('quality'),
            source.getAttribute('label')
          )
        );
      });
      qualityMenu.appendChild(createQualityMenuItem('quality-separator', '', '', 'separator'));
      qualityMenu.appendChild(createQualityMenuItem('quality-automatic', 'Automatic', '', 'Automatic'));
      qualityControl.appendChild(qualityMenuHolder);

      qualityButton.addEventListener('click', () => {
        if (qualityMenuHolder) {
          qualityMenuHolder.classList.toggle('is-open');
          qualityMenu.classList.toggle('is-open');
        }
      });
    } else {
      controls.querySelector('.js-video-quality').textContent = qualitySources[0].getAttribute('name');
    }
  }

  const subtitlesTracks = Array.prototype.slice.call(video.textTracks).filter(track => track.kind == 'subtitles');
  const captionsTracks = Array.prototype.slice.call(video.textTracks).filter(track => track.kind == 'captions');

  if (captionsTracks && captionsTracks.length !== 0) {
    setTimeout(function() {
      createTranscript(captionsTracks[0]);
    }, 1000);
  }

  if (!subtitlesTracks || subtitlesTracks.length == 0) {
    if (subtitlesControl) {
      subtitlesControl.classList.add('hidden');
    }
  } else {
    if (!subtitlesControl) return;
    var subtitleMenuButtons = [];
    var createMenuItem = function(id, lang, label) {
      var listItem = document.createElement('li');
      listItem.classList.add('if');
      if (label === 'separator') {
        listItem.classList.add('separator');
      }
      if (label !== 'separator') {
        var button = listItem.appendChild(document.createElement('button'));
        button.setAttribute('id', `if-video-${videoIndex}-${id}`);
        button.className = 'if';
        if (lang.length > 0) button.setAttribute('lang', lang);
        button.value = label;
        button.setAttribute('data-state', 'inactive');
        button.appendChild(document.createTextNode(label));
        button.addEventListener('click', function() {
          // Set all buttons to inactive
          subtitleMenuButtons.map(button => {
            button.setAttribute('data-state', 'inactive');
            button.classList.remove('is-active');
          });
          // Find the language to activate
          var lang = this.getAttribute('lang');

          for (var i = 0; i < subtitlesTracks.length; i++) {
            // For the 'subtitles-off' button, the first condition will never match so all will subtitles be turned off
            if (subtitlesTracks[i].language == lang) {
              subtitlesTracks[i].mode = 'showing';
              this.setAttribute('data-state', 'active');
              button.classList.add('is-active');
            } else {
              subtitlesTracks[i].mode = 'hidden';
              button.classList.remove('is-active');
            }
          }
          subtitlesMenuHolder.classList.toggle('is-open');
          subtitlesMenu.classList.toggle('is-open');
        });
        subtitleMenuButtons.push(button);
      }
      return listItem;
    };
    var subtitlesMenu;
    var subtitlesMenuHolder;
    if (subtitlesTracks) {
      var subtitlesMenuHolderDF = document.createDocumentFragment();
      subtitlesMenuHolder = subtitlesMenuHolderDF.appendChild(document.createElement('div'));
      subtitlesMenuHolder.classList.add('if');
      subtitlesMenuHolder.classList.add('dropdown-menu');
      subtitlesMenuHolder.classList.add('bottom');
      subtitlesMenuHolder.classList.add('right');
      subtitlesMenu = subtitlesMenuHolder.appendChild(document.createElement('ul'));
      subtitlesMenu.className = 'if';
      subtitlesMenu.appendChild(createMenuItem('subtitles-off', '', 'Off'));
      subtitlesMenu.appendChild(createMenuItem('subtitles-separator', '', 'separator'));
      for (var o = 0; o < subtitlesTracks.length; o++) {
        subtitlesMenu.appendChild(
          createMenuItem(
            'subtitles-' + subtitlesTracks[o].language,
            subtitlesTracks[o].language,
            subtitlesTracks[o].label
          )
        );
      }
      subtitlesControl.appendChild(subtitlesMenuHolder);
    }

    subtitlesButton.addEventListener('click', () => {
      if (subtitlesMenuHolder) {
        subtitlesMenuHolder.classList.toggle('is-open');
        subtitlesMenu.classList.toggle('is-open');
      }
    });
  }

  if (!captionsTracks || captionsTracks.length == 0) {
    if (captionsControl) {
      captionsControl.classList.add('hidden');
    }
  } else {
    if (!captionsControl) return;
    var captionMenuButtons = [];
    var createCaptionsMenuItem = function(id, lang, label) {
      var listItem = document.createElement('li');
      listItem.classList.add('if');
      if (label === 'separator') {
        listItem.classList.add('separator');
      }
      if (label !== 'separator') {
        var button = listItem.appendChild(document.createElement('button'));
        button.setAttribute('id', `if-video-${videoIndex}-${id}`);
        button.className = 'if';
        if (lang.length > 0) button.setAttribute('lang', lang);
        button.value = label;
        button.setAttribute('data-state', 'inactive');
        button.appendChild(document.createTextNode(label));
        button.addEventListener('click', function() {
          // Set all buttons to inactive
          captionMenuButtons.map(button => {
            button.setAttribute('data-state', 'inactive');
            button.classList.remove('is-active');
          });
          // Find the language to activate
          var lang = this.getAttribute('lang');
          for (var i = 0; i < captionsTracks.length; i++) {
            // For the 'captions-off' button, the first condition will never match so all will captions be turned off
            if (captionsTracks[i].language == lang) {
              captionsTracks[i].mode = 'showing';
              this.setAttribute('data-state', 'active');
              button.classList.add('is-active');
            } else {
              captionsTracks[i].mode = 'hidden';
              button.classList.remove('is-active');
            }
          }
          captionsMenuHolder.classList.toggle('is-open');
          captionsMenu.classList.toggle('is-open');
        });
        captionMenuButtons.push(button);
      }
      return listItem;
    };
    var captionsMenu;
    var captionsMenuHolder;
    if (captionsTracks && captionsControl) {
      var captionsMenuHolderDF = document.createDocumentFragment();
      captionsMenuHolder = captionsMenuHolderDF.appendChild(document.createElement('div'));
      captionsMenuHolder.classList.add('if');
      captionsMenuHolder.classList.add('dropdown-menu');
      captionsMenuHolder.classList.add('bottom');
      captionsMenuHolder.classList.add('right');
      captionsMenu = captionsMenuHolder.appendChild(document.createElement('ul'));
      captionsMenu.className = 'if';
      captionsMenu.appendChild(createCaptionsMenuItem('captions-off', '', 'Off'));
      captionsMenu.appendChild(createCaptionsMenuItem('captions-separator', '', 'separator'));
      for (var u = 0; u < captionsTracks.length; u++) {
        captionsMenu.appendChild(
          createCaptionsMenuItem(
            'captions-' + captionsTracks[u].language,
            captionsTracks[u].language,
            captionsTracks[u].label
          )
        );
      }
      captionsControl.appendChild(captionsMenuHolder);
    }

    captionsButton.addEventListener('click', () => {
      if (captionsMenuHolder) {
        captionsMenuHolder.classList.toggle('is-open');
        captionsMenu.classList.toggle('is-open');
      }
    });
  }

  if (seekerRange) {
    video.addEventListener('timeupdate', () => {
      if (video.currentTime != 0 && !isNaN(video.duration)) {
        seekerRange.value = (video.currentTime / video.duration) * seekerRange.max;
        seekerElapsed.textContent = createMediaTimestamp(parseInt(video.currentTime));
        seekerRemaining.textContent = `-${createMediaTimestamp(parseInt(video.duration - video.currentTime))}`;
      }
    });

    seekerRange.addEventListener('click', function(e) {
      const clickedValue = (e.offsetX * this.max) / this.offsetWidth;

      video.currentTime = (video.duration * clickedValue) / seekerRange.max;
      seekerElapsed.textContent = createMediaTimestamp(parseInt(video.currentTime));
      seekerRemaining.textContent = `-${createMediaTimestamp(parseInt(video.duration - video.currentTime))}`;
    });
  }

  const videoWorks = !!document.createElement('video').canPlayType;
  if (videoWorks) {
    video.controls = false;
  }

  // togglePlay toggles the playback state of the video.
  // If the video playback is paused or ended, the video is played
  // otherwise, the video is paused
  function ifVideoTogglePlay() {
    if (video.paused || video.ended) {
      video.play();
      videoContainer.classList.add('is-active');
      videoContainer.classList.remove('is-paused');
    } else {
      video.pause();
      videoContainer.classList.remove('is-active');
      videoContainer.classList.add('is-paused');
    }
  }

  // updatePlayButton updates the playback icon and tooltip
  // depending on the playback state
  function onPause() {
    pauseTime = video.currentTime;
    if (seekerRange) {
      if (video.currentTime != 0 && !isNaN(video.duration)) {
        seekerRange.value = (video.currentTime / video.duration) * seekerRange.max;
        seekerElapsed.textContent = createMediaTimestamp(parseInt(video.currentTime));
        seekerRemaining.textContent = `-${createMediaTimestamp(parseInt(video.duration - video.currentTime))}`;
      }
    }
    video.load();
  }
  function onPlay() {
    video.currentTime = pauseTime;
    if (seekerRange) {
      if (video.currentTime != 0 && !isNaN(video.duration)) {
        seekerRange.value = (video.currentTime / video.duration) * seekerRange.max;
        seekerElapsed.textContent = createMediaTimestamp(parseInt(video.currentTime));
        seekerRemaining.textContent = `-${createMediaTimestamp(parseInt(video.duration - video.currentTime))}`;
      }
    }
    video.play();
  }

  function toggleFullScreen() {
    if (document.fullscreenElement) {
      document.exitFullscreen().catch(err => console.error(err));
    } else {
      video.requestFullscreen();
    }
  }
  let timer = 0;
  // Add eventlisteners here
  playButton.addEventListener('click', ifVideoTogglePlay);
  video.addEventListener('play', onPlay);
  video.addEventListener('pause', onPause);
  video.addEventListener('click', () => {
    if (event.detail === 1) {
      timer = setTimeout(() => {
        ifVideoTogglePlay();
      }, 200);
    }
  });
  video.addEventListener('dblclick', () => {
    clearTimeout(timer);
    toggleFullScreen();
  });
  // video.addEventListener('mouseenter', showControls);
  // video.addEventListener('mouseleave', hideControls);
};

let videoObserver = new IntersectionObserver((entries, videoObserver) => {
  entries.forEach((entry, entryIndex) => {
    if (entry.intersectionRatio > 0) {
      const video = entry.target;
      videoObserver.unobserve(entry.target);

      initVideo(video, entryIndex);
    }
  });
});

document.querySelectorAll('video.if.player').forEach(video => {
  videoObserver.observe(video);
});

For youtube video

<div class="if video [is-active|is-paused]">
  <div class="if yt-player" id="yt-player-2"></div>
  <div class="if overlay">
    <span class="if title">If Villaförsäkring</span>
    <span class="if description">Se hur If Villaförsäkring förändrade Anna’s vardag</span>
    <button type="button" class="if play button secondary">
      Spela up filmen
    </button>
  </div>
</div>

JavaScript implementation example

var tag = document.createElement('script');

tag.src = '//www.youtube.com/iframe_api';
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

let youtubeVideos = document.querySelectorAll('.if.yt-player');

let players = [];

window.onPlayerReady = function(event, player_id) {
  console.info('YT: PLAYER READY');
  const video = event.target;
  console.log(video);
  const videoContainer = document.getElementById(player_id).parentElement;
  const videoOverlay = videoContainer.querySelector('.overlay');
  const playButton = videoContainer.querySelector('.button');
  function togglePlay() {
    if (videoContainer.classList.contains('is-active')) {
      video.pauseVideo();
    } else {
      video.playVideo();
    }

    console.info('YT: TOGGLING PLAY');
  }
  playButton.addEventListener('click', togglePlay);
};

window.onYouTubeIframeAPIReady = function() {
  console.info('YT: onYouTubeIframeAPIReady');
  players = [];
  // 5. The API calls this function when the player's state changes.
  //    The function indicates that when playing a video (state=1),
  //    the player should play for six seconds and then stop.
  var done = false;
  function onPlayerStateChange(event, player_id) {
    if (event.data == YT.PlayerState.PLAYING) {
      playVideo(event, player_id);
      console.info('YT: PLAYING');
    }
    if (event.data == YT.PlayerState.PAUSED) {
      pauseVideo(event, player_id);
      console.info('YT: PAUSED');
    }
    if (event.data == YT.PlayerState.ENDED && !done) {
      stopVideo(event, player_id);
      console.info('YT: ENDED');
      done = true;
    }
  }
  function playVideo(event, player_id) {
    const videoContainer = document.getElementById(player_id).parentElement;
    videoContainer.classList.add('is-active');
    videoContainer.classList.remove('is-paused');
    console.info('YT: PLAY VIDEO CALLED');
  }
  function pauseVideo(event, player_id) {
    const videoContainer = document.getElementById(player_id).parentElement;
    videoContainer.classList.remove('is-active');
    videoContainer.classList.add('is-paused');
    console.info('YT: PAUSE VIDEO CALLED');
  }
  function stopVideo(event, player_id) {
    const video = event.target;
    const videoContainer = document.getElementById(player_id).parentElement;
    video.stopVideo();
    videoContainer.classList.remove('is-active');
    videoContainer.classList.remove('is-paused');
    console.info('YT: STOP VIDEO CALLED');
  }

  youtubeVideos.forEach(player => {
    players.push(
      new YT.Player(player.id, {
        videoId: '-5V0RWaERSU',
        playerVars: {
          controls: 0,
          showinfo: 0,
          ecver: 2,
          rel: 0,
          iv_load_policy: 3,
          autoplay: 0,
          loop: 0
        },
        events: {
          onReady: e => {
            window.onPlayerReady(e, player.id);
          },
          onStateChange: e => {
            onPlayerStateChange(e, player.id);
          }
        }
      })
    );
  });
};

In Split Component

<div class="if block">
  <section class="if split">
    <div class="if container">
      <div class="if content">
        <h1 class="if heading medium">
          Drulleförsäkringen
        </h1>
        <p class="if text body">
          Allriskförsäkring, drulleförsäkring eller otursförsäkring – oavsett vad du kallar det så är det en försäkring
          som hjälper dig när du haft lite otur och till exempel välter kaffekoppen över datorn eller tappar
          solglasögonen i havet.
        </p>
        <a href="/asdasd" class="if standalone">Läs mer om vår drulleförsäkring</a>
      </div>
      <div class="if image">
        <div class="if video">
          <video
            class="if player"
            src="https://www.dreambroker.com/channel/qtauayyk/v8ukrs97/get/fullhd.mp4"
            poster="https://v.imgi.no/cxb3sdbcsn-MOODBOARD/2042"
          >
            Sorry, your browser doesn't support embedded videos, but don't worry, you can
            <a href="https://archive.org/details/BigBuckBunny_124">download it</a>
            and watch it with your favorite video player!
          </video>
          <div class="if overlay">
            <span class="if title">If Villaförsäkring</span>
            <span class="if description">Se hur If Villaförsäkring förändrade Anna’s vardag</span>
            <button type="button" class="if play button secondary">
              Spela up filmen
            </button>
          </div>
        </div>
      </div>
    </div>
  </section>
</div>

With captions

<div class="if video">
  <video
    title="Our visual identity"
    class="if player"
    disablePictureInPicture
    poster="https://www.dreambroker.com/channel/qtauayyk/v8ukrs97/get/poster?etag=1576140475000"
    src="https://www.dreambroker.com/channel/qtauayyk/v8ukrs97/get/fullhd.mp4"
    preload="none"
  >
    <track label="English" kind="subtitles" srclang="en" src="/videos/captions/vtt/if-design-en.vtt" default />
    Sorry, your browser doesn't support embedded videos, but don't worry, you can
    <a href="https://www.dreambroker.com/channel/qtauayyk/v8ukrs97/get/fullhd.mp4">download it</a>
    and watch it with your favorite video player!
  </video>
  <div class="if controls">
    <div class="if cc-control">
      <button type="button" class="if cc button"></button>
    </div>
  </div>
  <div class="if overlay">
    <span class="if title">Our visual identity</span>
    <span class="if description">
      Let us show you our new visual identity
    </span>
    <button class="if play button secondary" type="button">
      Play
    </button>
  </div>
</div>

Transcript

<div class="if panel is-expandable is-open">
  <div
    class="if title"
    aria-controls="video-0-transcription-content-title"
    tabindex="0"
    aria-expanded="true"
    id="video-0-transcription-expandable-title"
  >
    Transcript
  </div>
  <div class="if content" aria-live="off" aria-atomic="true" role="region" aria-relevant="all">
    <span class="if transcript-line">At If there is one thing that stands above everything else.</span>
    <span class="if transcript-line">One thing that drives us.</span>
    <span class="if transcript-line">Truly being there for our customers.</span>
    <span class="if transcript-line">That means putting our heart into our customers lives.</span>
    <span class="if transcript-line">Their relationships,</span>
    <span class="if transcript-line">their connections, the things they value</span>
    <span class="if transcript-line">and their peace of mind.</span>
    <span class="if transcript-line">So we've created a visual identity</span>
    <span class="if transcript-line">that peels away the unnecessary,</span>
    <span class="if transcript-line">that reduces complexity,</span>
    <span class="if transcript-line">making complex matters, easy to understand</span>
    <span class="if transcript-line">and draws attention to what matters the most</span>
    <span class="if transcript-line">in a simply personal way.</span>
    <span class="if transcript-line">Beige is our warm canvas that enables</span>
    <span class="if transcript-line">flexibility and structure to our offer.</span>
    <span class="if transcript-line">The blue plays a prominent role</span>
    <span class="if transcript-line">as our sender id, blue gives us the</span>
    <span class="if transcript-line">universal benefit of signaling attention</span>
    <span class="if transcript-line">into action and activation.</span>
    <span class="if transcript-line">A number of supporting colors are used to clarify</span>
    <span class="if transcript-line">our statistics and numbers,</span>
    <span class="if transcript-line">our images focus on what's most important,</span>
    <span class="if transcript-line">both in composition and by using depth of field.</span>
    <span class="if transcript-line">Our typography is inspired by handwriting</span>
    <span class="if transcript-line">If Sans is an airy and clean typeface.</span>
    <span class="if transcript-line">It has the ability to mimic acts of care and</span>
    <span class="if transcript-line">support, like the way it can connect</span>
    <span class="if transcript-line">its closest character.</span>
    <span class="if transcript-line">At its core we have a visual identity</span>
    <span class="if transcript-line">designed to bring clarity to our offer,</span>
    <span class="if transcript-line">an expression that is stunning in its simplicity</span>
    <span class="if transcript-line">while radiating emotion.</span>
    <span class="if transcript-line">A visual identity that emphasizes</span>
    <span class="if transcript-line">the very heart and soul of our brand.</span>
    <span class="if transcript-line">Truly being there, simple, personal.</span>
  </div>
</div>
Edit this section, Opens in new window

Changelog

Change Log

All notable changes to this project will be documented in this file. See Conventional Commits for commit guidelines.

14.0.0 (2021-11-09)

chore

  • 🤖 Rename util to utils (f78721f)

Code Refactoring

  • 💡 Rename scope and repository (3ea5423)
  • 💡 Use new navigation structure for documentation (415aee5), closes #490579

Documentation

  • ✏️ Update links and change navigation structure (0bfd27d), closes #490579

BREAKING CHANGES

  • 🧨 The scope for If Design System npm packages has now changed from

@if-design-system to @ids-core. We have also renamed the repository from if-design-system to ids-core

  • 🧨 Util is now renamed to Utils
  • 🧨 We have now changed the navigation structure for the documentation site.

Please update any saved links!

  • 🧨 Navigation structure has now changed. Please see release notes!

13.11.0 (2021-10-19)

Features

  • 🎸 Input field hot reload (eac76b7)

13.9.2 (2021-09-30)

Bug Fixes

  • 🐛 Complete the pseudo-element fix (1dcee2c)

13.6.3 (2021-09-17)

Bug Fixes

12.13.1 (2021-08-11)

Bug Fixes

12.10.0 (2021-06-29)

Bug Fixes

  • 🐛 Use correct classnames for video player menus (382cab8), closes #434090

12.6.0 (2021-05-27)

Bug Fixes

  • 🐛 Manually set firstPublished and lastModified (e83af7d)
  • 🐛 We don't need lastModified (e458a12)

12.0.0 (2021-05-05)

Bug Fixes

  • 🐛 Replace padding: none; with padding: 0; (0cdb9b6)
  • 🐛 Update references (c08f107)

Code Refactoring

Features

  • 🎸 Rename and extract and update hero with no image to (384eb77), closes #336508

BREAKING CHANGES

  • 🧨 All of the mixins have now been renamed
  • 🧨 Teasers are no more. It has been replaces with Lifestyle Navigational

Card, Text Navigational Card. Studio Teasers is gone, use Studio Navigational Card instead, which is based on the old Studio Crosslinks

  • 🧨 Notification is now renamed to Alert Banner
  • 🧨 This extracts the Hero variation with no image into a separate, design

updated component named Header

  • 🧨 Footer is now renamed to Global Footer
  • 🧨 Crosslinks have seized to exist. They are all extracted into separate

components. This commit converts crosslink buttons into the new component Shortcuts

9.3.0 (2021-02-02)

Bug Fixes

  • 🐛 Make it easier to embed youtube videos (3b16703), closes #336794

6.36.0 (2020-10-12)

Features

  • 🎸 Add updated focus styling for video (528fde5)

6.26.0 (2020-07-13)

Bug Fixes

  • 🐛 Fix youtube and live video alignment and placment (6730909)

6.22.0 (2020-07-01)

Features

  • 🎸 Add new color categories, update documentation (5496822)

6.17.3 (2020-05-25)

Bug Fixes

  • 🐛 Adjust icons for play when hovered and not (c194ab4)

6.16.1 (2020-05-20)

Bug Fixes

  • 🐛 Fix routing for dev server (295db6e)

6.13.0 (2020-05-04)

Features

  • 🎸 Add video controls and documentation (35ac1b1)

6.11.0 (2020-04-22)

Bug Fixes

12.13.1 (2021-08-11)

Bug Fixes

12.10.0 (2021-06-29)

Bug Fixes

  • 🐛 Use correct classnames for video player menus (382cab8), closes #434090

12.6.0 (2021-05-27)

Bug Fixes

  • 🐛 Manually set firstPublished and lastModified (e83af7d)
  • 🐛 We don't need lastModified (e458a12)

12.0.0 (2021-05-05)

Bug Fixes

  • 🐛 Replace padding: none; with padding: 0; (0cdb9b6)
  • 🐛 Update references (c08f107)

Code Refactoring

Features

  • 🎸 Rename and extract and update hero with no image to (384eb77), closes #336508

BREAKING CHANGES

  • 🧨 All of the mixins have now been renamed
  • 🧨 Teasers are no more. It has been replaces with Lifestyle Navigational

Card, Text Navigational Card. Studio Teasers is gone, use Studio Navigational Card instead, which is based on the old Studio Crosslinks

  • 🧨 Notification is now renamed to Alert Banner
  • 🧨 This extracts the Hero variation with no image into a separate, design

updated component named Header

  • 🧨 Footer is now renamed to Global Footer
  • 🧨 Crosslinks have seized to exist. They are all extracted into separate

components. This commit converts crosslink buttons into the new component Shortcuts

9.3.0 (2021-02-02)

Bug Fixes

  • 🐛 Make it easier to embed youtube videos (3b16703), closes #336794

6.36.0 (2020-10-12)

Features

  • 🎸 Add updated focus styling for video (528fde5)

6.26.0 (2020-07-13)

Bug Fixes

  • 🐛 Fix youtube and live video alignment and placment (6730909)

6.22.0 (2020-07-01)

Features

  • 🎸 Add new color categories, update documentation (5496822)

6.17.3 (2020-05-25)

Bug Fixes

  • 🐛 Adjust icons for play when hovered and not (c194ab4)

6.16.1 (2020-05-20)

Bug Fixes

  • 🐛 Fix routing for dev server (295db6e)

6.13.0 (2020-05-04)

Features

  • 🎸 Add video controls and documentation (35ac1b1)

6.11.0 (2020-04-22)

Bug Fixes

  • 🐛 Add sr only text for footer logo link (2971dd9)
  • 🐛 Use 100% height only for videos in live images (1bf1f35)

6.7.3 (2020-04-10)

Bug Fixes

  • 🐛 Add styling to subtitles for videos (1b1f839)

6.7.1 (2020-04-10)

Bug Fixes

  • 🐛 Remove min-width on cc button (43d0b5e)

6.7.0 (2020-04-10)

Features

  • 🎸 Add close caption/subtitles (9dade51)

6.6.0 (2020-04-09)

Bug Fixes

  • 🐛 Add min-height to video wrapper and ensure youtube video (78b50f6)

Features

  • 🎸 Make video player responsive (cda0569)

5.3.0 (2020-03-18)

Features

Edit this section, Opens in new window
Contact us, Opens in new window