⚠️ Svelte Reveal is currently in beta. Do you want to contribute? Do you want to report a bug?
Svelte Reveal is a library created with the purpose of helping Svelte users add reveal on scroll animations to their web applications in the easiest way possible. This library leverages the Intersection Observer API in order to know when to trigger the animations.
- Zero config Svelte action
- Highly customizable transitions
- Utilizes the Intersection Observer API
- TypeScript ready
- Usage
- Demo
- Why Svelte Reveal
- SvelteKit
- Options
- Global config
- API
- Suggestions
- Troubleshooting
- Funding
- Versioning
- Changelog
- License
-
Install the library. You can use either npm:
npm install -D svelte-reveal
yarn:
yarn add -D svelte-reveal
or pnpm:
pnpm add -D svelte-reveal
-
Import the library within your Svelte component:
<script> import { reveal } from 'svelte-reveal'; </script>
-
Add the imported reveal action to any DOM element you want:
<h1 use:reveal>Your title</h1> <p use:reveal={{ transition: "fade" }}>A paragraph</p>
If you want to use the action on a Svelte component, you need to pass the reveal options via props:
// App.svelte <script> import Heading from './Heading.svelte'; </script> <Heading useReveal={{ transition: "fade" }}>Hello world</Heading> // Heading.svelte <script lang="ts"> import { reveal } from 'svelte-reveal'; import type { RevealOptions } from 'svelte-reveal'; export let useReveal: RevealOptions; </script> <h1 use:reveal={ useReveal }> <slot /> </h1>
Using SvelteKit? Please read section "SvelteKit"
A Docker image is also available on DockerHub:
docker pull davekeehl/svelte-reveal:latest
You can also use the provided Dockerfile in the repository as a development environment. You can read more here.
In this Svelte REPL I created you can see Svelte Reveal in action.
If you happened to scout the internet for other similar libraries, you would have noticed that other authors have decided to create their own library using Svelte slots (similar to React children). There is nothing wrong with that approach, but in my opinion it goes a bit against one of Svelte's core purpose: writing more concise code. Having to wrap every to-be-transitioned component adds at least 2 extra lines of code each time, making your files unnecessarily bloated for such a simple add-on.
You might have also noticed people adding event listeners to the window object in order to transition elements, but in terms of performance it doesn't scale very well.
Instead, I decided to use Svelte actions, which are functions you can attach to a DOM element and that allow you to get access to that particular element and hook into its lifecycle. They take up considerably fewer lines of code, and so far I haven't encountered any obstacle or performance drawback. Morever, this library is backed by the Intersection Observer API, which is great for performance.
The way Svelte Reveal transitions the elements does not work well with SSR, which is enabled by default on SvelteKit. One way to get around this issue, is to wrap your top-most element or component in your app inside an if-block that is evaluated to true
only when its context has been updated, as in the following example.
<script>
import { afterUpdate } from 'svelte';
let show = false;
afterUpdate(() => {
show = true;
});
</script>
{#if show}
<your-element-or-component />
{/if}
Please create a new issue and submit a bug report in case of problems.
Depending on the use case, you can either use this library as-is (which applies some default styles), or customize it to your liking. If you choose to do so, you can pass an object to this action containing your own options to be applied.
Keep in mind that these options are applied to the single DOM element you add Svelte Reveal to. For global and more in-depth settings, refer to the API section.
Name | Type | Default | Description |
---|---|---|---|
disable | boolean |
false |
When set to false, the transition for the target element is disabled. |
debug | boolean |
false |
It enables/disables debugging mode for the target DOM element. This will log to the console the target DOM element, along with the options and config. In order to be able to use this mode, you are required to also set the ref property. |
ref | string |
"" |
When debug is set to true , you are required to specificy a ref string. When multiple DOM nodes have debug mode enabled, ref strings allow you to know to which DOM node a console log statement belongs to. |
highlightLogs | boolean |
false |
When set to true , the console logs of the target node are colored, making it easier to see them among many other logs. |
highlightColor | string |
"tomato" |
The color to use to color the console logs when the highlightLogs option is also set to true.Any valid CSS color can be used here. |
root | IntersectionObserver['root'] |
null |
The root element used by the Intersection Observer. |
rootMargin | IntersectionObserver['rootMargin'] |
"0px 0px 0px 0px" |
The root margin property of the Intersection Observer. |
threshold | number |
0.6 |
The threshold (in percentage from 0.0 to 1.0 ) property used by the Intersection Observer to know when its target element is considered visible. |
transition | Transition |
"fly" |
The type of transition that is triggered when the target node becomes visible. Read more in this subsection for a comprehensive explanation of the full list of available transitions. |
reset | boolean |
false |
When set to true, the node transitions out when out of view, and is revealed again when back in view.true . |
duration | number |
800 |
How long the transition lasts (in milliseconds). |
delay | number |
0 |
How long the transition is delayed (in milliseconds) before being triggered. |
easing | Easing |
"custom" |
The type of easing function applied to the transition .Check out the full list of available easing functions. The default easing function used by Svelte Reveal corresponds to the CSS ease transition timing function. |
customEasing | CustomEasing |
[0.25, 0.1, 0.25, 0.1] |
The individual weights of a custom cubic-bezier curve. This option is necessary when easing is set to custom . This website is great for previewing timing functions. |
x | number |
-20 |
The starting offset position in pixels on the x-axis of the "slide" transition.If x is negative, the element will transition from the left, else from the right. |
y | number |
-20 |
The starting offset position in pixels on the y-axis of the "fly" transition.If y is negative, the element will transition from the top, else from the bottom. |
rotate | number |
-360 |
The starting rotation offset in degrees of the "spin" transition.If rotate is positive, the element will spin clockwise, else counter-clockwise. |
opacity | number |
0 |
The starting opacity value in percentage of any transition. It can be a number between 0.0 and 1.0 . |
blur | number |
16 |
The starting blur value in pixels of the "blur" transition. |
scale | number |
0 |
The starting scale value in percentage of the "scale" transition. |
The following are all the transitions available. The names listed in the table below match the ones available in your source code. All transitions have the fade transition backed in.
Name | Description |
---|---|
fade | The element fades in gracefully. In practice: opacity: 0 -> 1 |
fly | The element fades in and performs a translation on the y-axis (vertical). In practice: opacity: 0 -> 1 and transform: translateY(-20px -> 0px) |
slide | The element fades in and performs a translation on the x-axis (horizontal). In practice: opacity: 0 -> 1 and transform: translateX(-20px -> 0px) |
blur | The element fades in and becomes unblurred. In practice: opacity: 0 -> 1 and filter: blur(8px -> 0px) |
scale | The element fades in and gets to the original size. In practice: opacity: 0 -> 1 and transform: scale(0 -> 1) width CSS property on the element to reveal. If you are not already using this property for other things, you can set it to width: fit-content . |
spin | The element fades in and gets to the original rotation degree. In practice: opacity: 0 -> 1 and transform: rotate(-360 -> 0) width CSS property on the element to reveal. If you are not already using this property for other things, you can use set it to width: fit-content . |
Among the available options, there are also some callback functions you can leverage to inject code during specific moments of the lifecycle of the DOM node attached to this action.
Name | Args | Return | Description |
---|---|---|---|
onRevealStart | (node: HTMLElement) |
void |
Function that gets fired when the node starts being revealed. |
onRevealEnd | (node: HTMLElement) |
void |
Function that gets fired when the node is fully revealed. |
onResetStart | (node: HTMLElement) |
void |
Function that gets fired when the reset option is set to true and the node starts transitioning out. |
onResetEnd | (node: HTMLElement) |
void |
Function that gets fired when the reset option is set to true and the node has fully transitioned out. |
onMount | (node: HTMLElement) |
void |
Function that gets fired when the node is mounted on the DOM. |
onUpdate | (node: HTMLElement) |
void |
Function that gets fired when the action options are updated. |
onDestroy | (node: HTMLElement) |
void |
Function that gets fired when the node is unmounted from the DOM. |
This library is globally configured as follows right of out the box:
Parameter | (children) | (children) | Type | Default | Description |
---|---|---|---|---|---|
dev | boolean |
true |
Globally enables/disables all logs. | ||
once | boolean |
false |
Performs the reveal effect only once when set to true . When set to true , refreshing the page doesn't re-run them. |
||
responsive | Responsive |
Information about how the library handles responsiveness. It can be used to enable/disable the reveal effect on some devices. | |||
mobile | IDevice |
Object containing information about responsiveness on mobile devices. | |||
enabled | boolean |
true |
Whether the device supports the reveal effect on mobile devices. | ||
breakpoint | number |
425 |
The viewport width upper limit that a mobile device can be targeted to work in. | ||
tablet | IDevice |
Object containing information about responsiveness on tablet devices. | |||
enabled | boolean |
true |
Whether the device supports the reveal effect on tablet devices. | ||
breakpoint | number |
768 |
The viewport width upper limit that a tablet device can be targeted to work in. | ||
laptop | IDevice |
Object containing information about responsiveness on laptop devices. | |||
enabled | boolean |
true |
Whether the device supports the reveal effect on laptop devices. | ||
breakpoint | number |
1440 |
The viewport width upper limit that a laptop device can be targeted to work in. | ||
desktop | IDevice |
Object containing information about responsiveness on desktop devices. | |||
enabled | boolean |
true |
Whether the device supports the reveal effect on desktop devices. | ||
breakpoint | number |
2560 |
The viewport width upper limit that a desktop device can be targeted to work in. |
⚠️ If you want to customise the behavior of a single DOM node, you are supposed to use the options.
Svelte Reveal also exposes several functions you can call to change the default options and global configuration of this library. Since these functions operate on a global level across all components using Svelte Reveal, you are supposed to only call them from a single file, otherwise you'll keep overriding the default options and global config from multiple points.
If you need/want to considerably customize the behavior of this library, I suggest creating a dedicated file (e.g. reveal.config.js) and to import it from the top-most component in the components tree of your project. Within that file you can then call the API functions to set global settings or shared transition properties.
// App.svelte
<script>
import '../reveal.config';
</script>
<div>{ your markup goes here }</div>
Since this library has been built using TypeScript, there are many custom types used throughout the entire codebase. The following types are the main ones used by the API:
type Device = 'mobile' | 'tablet' | 'laptop' | 'desktop';
interface IDevice {
enabled: boolean;
breakpoint: number;
}
interface Responsive {
[P in Device]: IDevice;
}
interface IObserverOptions {
root: IntersectionObserver['root'];
rootMargin: IntersectionObserver['rootMargin'];
threshold: number;
}
interface RevealConfig {
dev: boolean;
once: boolean;
responsive: Responsive;
}
interface RevealOptions {
disable?: boolean;
debug?: boolean;
ref?: string;
highlightLogs?: boolean;
highlightColor?: string;
root?: IntersectionObserver['root'];
rootMargin?: IntersectionObserver['rootMargin'];
threshold?: number;
...
onUpdate?: (node: HTMLElement) => void;
onDestroy?: (node: HTMLElement) => void;
}
Args | Return | Description |
---|---|---|
(dev: boolean) |
RevealConfig |
Sets the development mode status. |
Args | Return | Description |
---|---|---|
(once: boolean) |
RevealConfig |
Sets the reveal animations activation status on page reload. |
Args | Return | Description |
---|---|---|
(device: Device, status: boolean) |
RevealConfig |
Sets the status of a device. |
Args | Return | Description |
---|---|---|
(devices: Device[], status: boolean) |
RevealConfig |
Sets the status of multiple devices. |
Args | Return | Description |
---|---|---|
(device: Device, breakpoint: number) |
RevealConfig |
Sets the breakpoint of a device. |
Args | Return | Description |
---|---|---|
(device: Device, settings: IDevice) |
RevealConfig |
Sets the settings of a device. |
Args | Return | Description |
---|---|---|
(responsive: Responsive) |
RevealConfig |
Updates how responsiveness is handled by the library. |
Args | Return | Description |
---|---|---|
(root: IntersectionObserver['root']) |
IObserverOptions |
Sets the Intersection Observer root element. |
Args | Return | Description |
---|---|---|
(rootMargin: IntersectionObserver['rootMargin']) |
IObserverOptions |
Sets the Intersection Observer rootMargin property. |
Args | Return | Description |
---|---|---|
(threshold: number) |
IObserverOptions |
Sets the Intersection Observer threshold property. |
Args | Return | Description |
---|---|---|
(observerConfig: IObserverOptions) |
IObserverOptions |
Sets the Intersection Observer configuration. |
Args | Return | Description |
---|---|---|
(userConfig: RevealConfig) |
RevealConfig |
Updates the global configuration of this library. |
Args | Return | Description |
---|---|---|
(options: RevealOptions) |
RevealOptions |
Updates the default options to be used for the reveal effect. |
It's not by any means required, but in order to take full advantage of this library, I suggest creating some environment variables to keep track of the environment the application is currently in (e.g. development, production) and to leverage NPM scripts to update those variables. This article explains well this concept.
That way you can for example set the config dev
property to false
when in production and avoid exposing console logs to the end users.
If you use SvelteKit you can import the dev
variable from the $app/environment module. If you are using Vite, you can use the import.meta.env.DEV
available from its env variables and modes.
Feel free to open a new issue in case of any problems.
This project uses Semantic Versioning to keep track of its version number.