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>
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>
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}>
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.
Top comments (2)
tried:
and the whole thing collapsed
you may have a hint
I see. It's fragile. No details, no hint I am afraid :)