DEV Community

Ilia Mikhailov
Ilia Mikhailov

Posted on • Updated on • Originally published at codechips.me

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.

Oldest comments (2)

Collapse
 
peeweescott profile image
peeweeScott

tried:
and the whole thing collapsed
you may have a hint

Collapse
 
codechips profile image
Ilia Mikhailov

I see. It's fragile. No details, no hint I am afraid :)