Let's build a Svelte fullscreen component

codechips

Ilia Mikhailov

Posted on January 4, 2020

Let's build a Svelte fullscreen component

Sometimes you have the need to go fullscreen, especially when building some fun internal dashboards. Because, you know, they are fun to build. Useful too. So why not build one in Svelte for a change? Let's see how easy it is to slap together a fullscreen component with this awesome framework.

Altough, it might not look like much, but you will learn about:

  • Svelte's slots
  • Exposing sub component's properties to parent
  • Adding stylesheets to document's head at runtime
  • Using the onMount callback
  • Svelte's reactivity
  • And maybe even some CSS

App.svelte

Replace your App.svelte with the code below. We are importing a fullscreen component that we haven't defined yet. No worries, let the compiler whine for a few minutes. It can wait.

<!-- App.svelte -->

<script>
  import Fullscreen from "./Fullscreen.svelte";
</script>

<style>
  h2 {
    text-align: center;
    font-size: 2rem;
  }
</style>

<Fullscreen let:isFull>
  <div>
    <img
      src="https://media.giphy.com/media/vCKC987OpQAco/giphy.gif"
      alt="Yes you are!" />
    <h2>
      {#if isFull}I am now in fullscreen!{/if}
    </h2>
  </div>
</Fullscreen>

Enter fullscreen mode Exit fullscreen mode

If you look at the code you can see that we passing a div as a child component to our fullscreen component. Our fullscreen component is also exposing a property called isFull to the parent. We can use it to make decisions if we want to hide something when in fullscreen mode and other useful things. Let's keep things basic.

Fullscreen.svelte

Here is our fullscreen component. Take a quick look and let's go through it below.

<!-- Fullscreen.svelte -->

<script>
  import { onMount } from "svelte";

  // define initial component state
  let isFull = false;
  let fsContainer = null;

  // boring plain js fullscreen support stuff below
  const noop = () => {};

  const fullscreenSupport = !!(
    document.fullscreenEnabled ||
    document.webkitFullscreenEnabled ||
    document.mozFullScreenEnabled ||
    document.msFullscreenEnabled ||
    false
  );

  const exitFullscreen = (
    document.exitFullscreen ||
    document.mozCancelFullScreen ||
    document.webkitExitFullscreen ||
    document.msExitFullscreen ||
    noop
  ).bind(document);

  const requestFullscreen = () => {
    const requestFS = (
      fsContainer.requestFullscreen ||
      fsContainer.mozRequestFullScreen ||
      fsContainer.webkitRequestFullscreen ||
      fsContainer.msRequestFullscreen ||
      noop
    ).bind(fsContainer);
    requestFS();
  };

  onMount(() => {
    // Add the icon stylesheet dynamically
    const link = document.createElement("link");
    link.rel = "stylesheet";
    link.href = "https://fonts.googleapis.com/icon?family=Material+Icons";
    document.head.appendChild(link);

    // remove the link when component is unmounted
    return () => {
      link.parentNode.removeChild(link);
    };
  });

  // handler for the fullscreen button
  const fsToggle = () => {
    if (!fullscreenSupport) return;

    if (isFull) {
      exitFullscreen();
    } else {
      requestFullscreen(fsContainer);
    }
    isFull = !isFull;
  };

  // the icon name is computed automagically based
  // on the state of the screen
  $: icon = isFull ? "fullscreen_exit" : "fullscreen";
</script>

<style>
  .isFull {
    width: 100vw;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #fff;
  }
  button {
    color: #000;
    position: absolute;
    right: 20px;
    bottom: 20px;
  }
</style>

<div class="fs" class:isFull bind:this={fsContainer}>
  <slot {isFull} />
  {#if fullscreenSupport}
    <button on:click={fsToggle}>
      <i class="material-icons md-36">{icon}</i>
    </button>
  {/if}
</div>

Enter fullscreen mode Exit fullscreen mode

At the top we are defining two state variables. isFull is a boolean that indicates if component is in fullscreen mode. This is also a variable that we'are exposing in the slot <slot {isFull} />, so our parent component can use it if it needs. We are also binding the DOM node of the fullscreen div to the fsContainer variable that we use in our code to trigger fullscreen state.

<div class="fs" class:isFull bind:this={fsContainer}>
Enter fullscreen mode Exit fullscreen mode

In the code snippet above we are also using Svelte's nifty way of setting a CSS class on the component depending on the variable state. You can see that we defined a .isFull class in the style tag. There is also a way to use a pseudo CSS class :fullscreen when then component is in fullscreen mode, but for some reason I couldn't get it to work with Svelte's CSS scoping.

Conclusion

As you see, it's really easy to build custom components in Svelte because it's just vanilla JS with some sugar sprinkled on top. Sometimes it's easier to just copy and paste code and tweak it to your own desire, than to install a package from NPM.

💖 💪 🙅 🚩
codechips
Ilia Mikhailov

Posted on January 4, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related