Back to Video-guidelines

CSS ComponentThe latest version of this package is: 17.0.30-alpha.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@17.0.30-alpha.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.22.2 (2022-05-03)

Miscellaneous chores

  • package locks: update package locks (813eac7)

14.20.1 (2022-04-19)

Miscellaneous chores

  • changelog: regenerate all CHANGELOG.md files (64ab385) , closes #586342
  • changelog: regenerate all changelogs after updating changelog generation (70789c9) , closes #587270

14.18.3 (2022-04-13)

Bug Fixes

  • changelog: generate new CHANGELOG.md files for root and packages (349fda4) , closes #586063 . We regenerate the files to include all relevant commits and to use conventional-commits at 100%

14.16.0 (2022-04-07)

Bug Fixes

  • 🐛 Add missing imports for global CSS Variables (fbf6f06) , closes #582437

14.9.0 (2022-03-03)

Miscellaneous chores

14.8.1 (2022-02-23)

Bug Fixes

  • 🐛 Add missing imports of typography CSS variables (e716c65) , closes #559412

reinstall (d425056)

bootstrap (9a713df)

merge (2b1c5f1)

reinstall (5221600)

reinstall (147df55)

  • use correct versions (f1b5deb)

  • Add engines for all packages (e95dfff)

reinstall (afce1f2)

reinstall (67f3140)

  • Add changelog.md to files (3338314)

Reinstall (a2abf51)

14.2.2 (2021-12-10)

Code Refactoring

reinstall (885c74b)

  • fix changelogs manually (b1232b4)

reinstall (545a069)

reinstall (e149c2c)

13.12.3 (2021-11-09)

⚠ 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!

Documentation Updates

  • ✏️ Make variations tables more condensed (4344a3a)

  • ✏️ Move position of the quick links (5cb0897)

  • ✏️ Remove unneeded margins for shortcuts (36c7e8d)

  • ✏️ Separate out CSS documentation (55cc77d) , closes #467386

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

Code Refactoring

  • 💡 Categorize components (9965266) , closes #490579

  • 💡 Reduce spacing tokens, use correct size tokens (97aa461)

  • 💡 Rename scope and repository (3ea5423)

  • 💡 Use new navigation structure for documentation (415aee5) , closes #490579

  • another change in the structure (38a0d2e)

Miscellaneous chores

bootstrap (6fc1ed8)

  • fix all old references to util (d57bf17)

  • prepare for merge (0184490)

reinstall (da80dba)

  • Rename scope and repo (257684e)

  • use correct version for utils (49e72d9)

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.7.0 (2021-09-22)

Documentation Updates

  • ✏️ Update linking layout and naming (15c383b)

13.6.3 (2021-09-17)

Bug Fixes

13.6.0 (2021-09-08)

Documentation Updates

  • Use default shortcut listing for demo links (a746602)

13.5.0 (2021-09-06)

Documentation Updates

  • ✏️ Update documentation for navigation card change (0379db5)

  • 🤖 Use node v14 (4009973)

bootstrap (d23e139)

  • 🤖 Use correct order for diff (cc6a4fd)

12.14.1 (2021-08-12)

Miscellaneous chores

  • 🤖 Add ci task to package.json without tests (21222e0) , closes #457627

12.13.1 (2021-08-11)

Bug Fixes

  • 🐛 Whitelist docs dir for npm packaging (1a5cfd0) , closes #457621

  • 🤖 Remove .gitignore, use npm package.json files instead, ignore zip files for npm pack (49f0269) , closes #412081 . This will whitelist files to be used in "npm pack"

  • 🤖 Reinstall (e660696)

12.10.0 (2021-06-29)

Bug Fixes

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

  • 🤖 Update published date (61e7ccf)

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)

⚠ 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

Features

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

Bug Fixes

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

  • 🐛 Update references (c08f107)

Code Refactoring

Miscellaneous chores

  • 🤖 Convert typography tokens from theo to SD (e48f255)

  • 🤖 Convert util tokens from theo to style-dictionary (99fb4f5)

  • 🤖 Finalize breakpoint token conversion (f50ea0d)

  • 🤖 Reinstall (2c763ea)

  • 🤖 Reinstall (69e1a5b)

  • 🤖 Update all design token references (c640d15)

  • 🤖 Update menu references in video component (c369ecf)

  • 🤖 Update references to util variables (b79ec36)

  • 🤖 Updating links (70f166e)

rebuild (7edb430)

10.2.2 (2021-03-10)

Documentation Updates

  • ✏️ Fix broken demo links (470b377)

10.2.1 (2021-03-05)

Documentation Updates

  • ✏️ Use correct class attribute (9755532)

  • 🤖 Rename Change Log to Changelog (d412e63)

  • 🤖 Remove all references to sketch (35fc554) , closes #339203

  • 🤖 Update package fields (200c0af)

  • reinstall packages (fcfacf4)

9.3.0 (2021-02-02)

Bug Fixes

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

Documentation Updates

  • ✏️ Start to fix documentation layout for video component (f2e19bd)

  • ✏️ Update documentation layout for video component (9d5da30)

  • 🤖 Update demo page for video (5177eb8)

8.0.0 (2020-12-14)

Code Refactoring

  • 💡 Replace old block board with new Split Component (49ca4a3)

6.43.3 (2020-11-03)

Miscellaneous chores

  • 🤖 Manually set version (e4d9ca6)

  • 🤖 Rename repository from guybrush to if-design-system (c18bccd)

reinstall (2cefe15)

6.36.0 (2020-10-12)

Features

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

Miscellaneous chores

  • 🤖 Add what-input to demo and dev files (56801b7)

  • 🤖 Rename focus style mixins (e18b688)

6.29.4 (2020-09-09)

Documentation Updates

  • ✏️ Use correct strong element with if class (6b484df)

6.29.3 (2020-09-07)

Documentation Updates

  • ✏️ Merge atoms/molecules/organisms into components (90ed590)

6.26.12 (2020-08-03)

Documentation Updates

  • ✏️ Update documentation for the new registry (3e7ba20)

Miscellaneous chores

  • 🤖 lerna bootstrap (d835ec9)

  • 🤖 Temporarily remove package-lock.json-files (87b3f7f)

  • 🤖 Update references to new scope (b5575dd)

6.26.10 (2020-07-14)

Miscellaneous chores

  • 🤖 Manually update some links (ecc0133)

  • 🤖 Update CHANGELOG.md links to workitems and commits (ab2887b)

6.26.0 (2020-07-13)

Bug Fixes

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

6.23.0 (2020-07-01)

Miscellaneous chores

reinstall (1ab1527)

6.22.0 (2020-07-01)

Features

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

Documentation Updates

  • ✏️ Update documentation layout (816053b)

Miscellaneous chores

  • 🤖 Search and replace old color usage (3e5abb0)

6.21.6 (2020-06-11)

Miscellaneous chores

  • 🤖 Remove .zip files from .npmignore (b3bc7dc)

6.19.0 (2020-06-02)

Miscellaneous chores

reinstall (3416c65)

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)

Documentation Updates

  • ✏️ Use full instead of emphasize in doc examples (a2dda1d)

6.15.5 (2020-05-15)

Miscellaneous chores

gatsbify (0e07d68)

  • prepped and ready to separate documentation site from code (d3e1fd9)

  • pruning and reinstalling (5cda0bc)

reinstall (939dae6)

reinstall (cae55fb)

  • Remove livingcss data and add frontmatter data (b384946)

6.15.4 (2020-05-14)

Miscellaneous chores

6.15.2 (2020-05-11)

Miscellaneous chores

6.15.0 (2020-05-07)

Miscellaneous chores

6.13.0 (2020-05-04)

Features

  • 🎸 Add video controls and documentation (35ac1b1)

Miscellaneous chores

  • 🤖 Continue developing the video UI (db7ef1e)

  • 🤖 Start to add video controls (c9542df)

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.10.9 (2020-04-22)

Miscellaneous chores

  • 🤖 Add *.zip-files to .npmignore-files (062b8b0)

6.10.6 (2020-04-17)

Miscellaneous chores

6.9.1 (2020-04-16)

Documentation Updates

  • ✏️ Use correct badge color in README.md (03b563e)

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)

Features

  • 🎸 Make video player responsive (cda0569)

Bug Fixes

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

Documentation Updates

  • ✏️ Change edit this document to edit this section (791b646)

6.5.3 (2020-04-06)

Documentation Updates

  • ✏️ Some more sg updates and tweaks (d1d6802)

6.3.4 (2020-04-01)

Miscellaneous chores

  • 🤖 Use more of if styling on documentation site (2eaf386)

6.0.0 (2020-03-23)

Documentation Updates

  • ✏️ Remove preload from video tags to prevent loading (71eb610)

5.3.0 (2020-03-18)

Features

Miscellaneous chores

  • packages: remove most packages, this is a do-over (7da5b50)
Edit this section, Opens in new window
Contact us, Opens in new window