Svelte component and helper functions for creating easy dynamic layouts with CSS media queries.
[!Important] Since this package relies on CSS Media Query Listeners, content outside the Default slot is not rendered server-side. If you need conditional layouts based on screen sizes, and need SSR compatibility, use CSS
@media
queries in your styles instead.
[!Note] v1.0 is currently in progress, and includes a rewrite of the component and helper function for use with Svelte v5's Runes. This readme references new functionality not present in the current version - the current version can be found under the
v0
branch.
Install using yarn / pnpm / npm:
yarn add -D svelte-breakpoints
pnpm add -D svelte-breakpoints
npm install --save-dev svelte-breakpoints
Import useMediaQuery
and provide a valid CSS media query. It will return a readable boolean store representing whether the media query matches.
<script lang="ts">
import { useMediaQuery } from 'svelte-breakpoints';
const isMobile: Readable<boolean> = useMediaQuery('(max-width: 600px)');
$effect(() => {
if ($isMobile) {
console.log('Not desktop!');
}
});
</script>
{#if $isMobile}
<!-- do something -->
{/if}
It can be used for any valid CSS media queries.
import { useMediaQuery } from 'svelte-breakpoints';
const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');
subscribeToQueries
allows subscribing to the state of multiple MQLs, as well as updating them after the initial function call. It returns a Readable store containing the names of all matching queries in an array.
<script lang="ts">
import { subscribeToQueries } from 'svelte-breakpoints';
const mediaQueries = {
reduceMotion: '(prefers-reduced-motion: reduce)',
prefersDark: '(prefers-color-scheme: dark)'
};
const matches: Readable<string[]> = subscribeToQueries(mediaQueries);
$effect(() => {
if ($matches.includes('reduceMotion')) {
console.log('Reduced motion is enabled');
}
});
</script>
Import the component and pass in the media queries to use. By default, the component will only render the last matching snippet, or the 'default' snippet if no queries match, finally falling back to the Default Slot if no snippets are provided. Passing renderAll
will render all matching snippets rather than the last matching.
<script lang="ts">
import Breakpoints from 'svelte-breakpoints';
const mediaQueries = {
small: '(min-width: 0px)',
medium: '(min-width: 768px)',
large: '(min-width: 1024px)',
};
</script>
<!-- Using snippets as children -->
<Breakpoints queries={mediaQueries}>
{#snippet small()}
<p>Screen is less than 768px wide</p>
{/snippet}
{#snippet medium()}
<p>Screen is at least 768px wide</p>
{/snippet}
{#snippet large()}
<p>Screen is at least 1024px wide</p>
{/snippet}
</Breakpoints>
<!-- Rendering all matching snippets -->
<Breakpoints queries={mediaQueries} renderAll>
{#snippet small()}
<p>Screen is less than 768px wide</p>
{/snippet}
{#snippet medium()}
<p>Screen is at least 768px wide</p>
{/snippet}
{#snippet large()}
<p>Screen is at least 1024px wide</p>
{/snippet}
</Breakpoints>
You can also define snippets elsewhere and pass them in via the content
prop.
fallback
is reserved for fallback content if no snippets match. If no fallback
is provided, the Default slot's content will be rendered.
{#snippet fallback()}
<p>I'm defined elsewhere!</p>
{/snippet}
{#snippet small()}
<p>I'm defined elsewhere too!</p>
{/snippet}
<!-- ... -->
<Breakpoints queries={mediaQueries} content={{ small }} {fallback} />
Binding to component.matches
returns a Readable store containing the names of all matching queries.
<script lang="ts">
let componentInstance: { matches: Readable<(string | number)[]> } = $state({ matches: readable([]) }),
{ matches } = $derived(componentInstance);
</script>
<Breakpoints queries={mediaQueries} bind:this={componentInstance}>
{#if $matches.includes('large')}
<p>Screen is at least 1024px wide</p>
{:else}
<p>Screen is less than 1024px wide</p>
{/if}
</Breakpoints>
Since any valid CSS media queries can be used, you can also use queries such as prefers-color-scheme
, prefers-reduced-motion
, etc.
<script lang="ts">
import Breakpoints from 'svelte-breakpoints';
const mediaQueries = {
reducedMotion: '(prefers-reduced-motion: reduce)',
};
</script>
<Breakpoints queries={mediaQueries}>
{#snippet reducedMotion()}
<p>Reduced motion is enabled</p>
{/snippet}
{#snippet default()}
<p>Reduced motion is not enabled</p>
{/snippet}
</Breakpoints>
To build the package, install deps with pnpm install
, then run pnpm build
. This will output the compiled files to the dist
directory. To run the demo app, use pnpm dev
.
To run all Playwright and Vitest tests, use pnpm test
.
If you find any issues, please open a new issue, or submit a pull request!
This project is licensed under the MIT License - see the LICENSE file for details.