DEV Community

Ilia Mikhailov
Ilia Mikhailov

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

6 1

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.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top 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 :)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Instrument, monitor, fix: a hands-on debugging session

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️