Spec Registry
Help your agents use open-source better. Learn more.
Find usage specs for your project’s dependencies
- Author
- tessl
- Last updated
- Spec files
npm-svelte
Describes: npm/svelte
- Description
- A cybernetically enhanced web application framework that compiles to highly optimized JavaScript with reactive state management and component-based architecture.
- Author
- tessl
- Last updated
reactivity-window.md docs/
1# Window Reactivity23Svelte provides reactive values for common window properties that automatically update when the browser window changes. These are particularly useful for responsive design and window-based interactions.45## Capabilities67### Window Dimensions89Reactive values for window size properties.1011```typescript { .api }12/**13* Reactive view of window.innerWidth14* @since 5.11.015*/16const innerWidth: ReactiveValue<number | undefined>;1718/**19* Reactive view of window.innerHeight20* @since 5.11.021*/22const innerHeight: ReactiveValue<number | undefined>;2324/**25* Reactive view of window.outerWidth26* @since 5.11.027*/28const outerWidth: ReactiveValue<number | undefined>;2930/**31* Reactive view of window.outerHeight32* @since 5.11.033*/34const outerHeight: ReactiveValue<number | undefined>;35```3637**Usage Examples:**3839```typescript40import { innerWidth, innerHeight, outerWidth, outerHeight } from "svelte/reactivity/window";4142// Responsive breakpoints43const isSmallScreen = $derived(innerWidth.current < 768);44const isMediumScreen = $derived(innerWidth.current >= 768 && innerWidth.current < 1024);45const isLargeScreen = $derived(innerWidth.current >= 1024);4647// Aspect ratio calculations48const aspectRatio = $derived(49innerWidth.current && innerHeight.current50? innerWidth.current / innerHeight.current51: 16/952);5354// Window size for canvas or dynamic layouts55let canvas;56$effect(() => {57if (canvas && innerWidth.current && innerHeight.current) {58canvas.width = innerWidth.current;59canvas.height = innerHeight.current;60}61});6263// Responsive component behavior64const itemsPerRow = $derived(() => {65if (!innerWidth.current) return 1;66if (innerWidth.current < 600) return 1;67if (innerWidth.current < 900) return 2;68if (innerWidth.current < 1200) return 3;69return 4;70});71```7273### Window Position7475Reactive values for window position properties.7677```typescript { .api }78/**79* Reactive view of window.screenLeft (updated in requestAnimationFrame)80* @since 5.11.081*/82const screenLeft: ReactiveValue<number | undefined>;8384/**85* Reactive view of window.screenTop (updated in requestAnimationFrame)86* @since 5.11.087*/88const screenTop: ReactiveValue<number | undefined>;89```9091**Usage Examples:**9293```typescript94import { screenLeft, screenTop } from "svelte/reactivity/window";9596// Track window position97const windowPosition = $derived({98x: screenLeft.current || 0,99y: screenTop.current || 0100});101102// Multi-monitor awareness103$effect(() => {104const x = screenLeft.current;105const y = screenTop.current;106107if (x !== undefined && y !== undefined) {108console.log(`Window moved to (${x}, ${y})`);109110// Adjust behavior based on screen position111if (x < 0 || y < 0) {112console.log("Window is on a secondary monitor");113}114}115});116```117118### Scroll Position119120Reactive values for window scroll position.121122```typescript { .api }123/**124* Reactive view of window.scrollX125* @since 5.11.0126*/127const scrollX: ReactiveValue<number | undefined>;128129/**130* Reactive view of window.scrollY131* @since 5.11.0132*/133const scrollY: ReactiveValue<number | undefined>;134```135136**Usage Examples:**137138```typescript139import { scrollX, scrollY } from "svelte/reactivity/window";140141// Scroll-based effects142const isScrolled = $derived((scrollY.current || 0) > 100);143const scrollProgress = $derived(() => {144const y = scrollY.current || 0;145const maxScroll = document.documentElement.scrollHeight - window.innerHeight;146return Math.min(y / maxScroll, 1);147});148149// Sticky header behavior150let header;151$effect(() => {152if (header) {153header.classList.toggle("scrolled", isScrolled);154}155});156157// Parallax effects158let parallaxElement;159$effect(() => {160if (parallaxElement && scrollY.current !== undefined) {161const offset = scrollY.current * 0.5;162parallaxElement.style.transform = `translateY(${offset}px)`;163}164});165166// Hide/show elements based on scroll direction167let lastScrollY = 0;168let scrollDirection = $state("up");169170$effect(() => {171const currentScrollY = scrollY.current || 0;172173if (currentScrollY > lastScrollY) {174scrollDirection = "down";175} else if (currentScrollY < lastScrollY) {176scrollDirection = "up";177}178179lastScrollY = currentScrollY;180});181```182183### Network Status184185Reactive value for network connectivity.186187```typescript { .api }188/**189* Reactive view of navigator.onLine190* @since 5.11.0191*/192const online: ReactiveValue<boolean | undefined>;193```194195**Usage Examples:**196197```typescript198import { online } from "svelte/reactivity/window";199200// Network status indicator201const isOnline = $derived(online.current ?? true);202const networkStatus = $derived(isOnline ? "online" : "offline");203204// Conditional behavior based on connectivity205$effect(() => {206if (isOnline) {207console.log("Connected - syncing data");208syncOfflineData();209} else {210console.log("Disconnected - switching to offline mode");211enableOfflineMode();212}213});214215// Queue operations when offline216let pendingOperations = $state([]);217218function performOperation(operation) {219if (isOnline) {220executeOperation(operation);221} else {222pendingOperations = [...pendingOperations, operation];223}224}225226$effect(() => {227if (isOnline && pendingOperations.length > 0) {228// Process queued operations when back online229pendingOperations.forEach(executeOperation);230pendingOperations = [];231}232});233```234235### Device Pixel Ratio236237Reactive value for device pixel ratio (display scaling).238239```typescript { .api }240/**241* Reactive view of window.devicePixelRatio242* Note: Behavior differs between browsers - Chrome responds to zoom, Firefox/Safari don't243* @since 5.11.0244*/245const devicePixelRatio: {246get current(): number | undefined;247};248```249250**Usage Examples:**251252```typescript253import { devicePixelRatio } from "svelte/reactivity/window";254255// High DPI canvas rendering256let canvas;257let ctx;258259$effect(() => {260if (canvas && ctx) {261const ratio = devicePixelRatio.current || 1;262const rect = canvas.getBoundingClientRect();263264// Scale canvas for high DPI displays265canvas.width = rect.width * ratio;266canvas.height = rect.height * ratio;267268ctx.scale(ratio, ratio);269270// Redraw with high DPI scaling271redrawCanvas();272}273});274275// Image loading based on pixel density276const imageSource = $derived(() => {277const ratio = devicePixelRatio.current || 1;278279if (ratio >= 3) {280return "image@3x.jpg";281} else if (ratio >= 2) {282return "image@2x.jpg";283} else {284return "image.jpg";285}286});287288// CSS-in-JS with device pixel ratio289const styles = $derived(() => ({290fontSize: `${16 * (devicePixelRatio.current || 1)}px`,291borderWidth: `${1 / (devicePixelRatio.current || 1)}px`292}));293```294295## Server-Side Behavior296297All window reactivity values return `undefined` on the server since window properties are not available during server-side rendering.298299```typescript300// Safe server-side usage301const isMobile = $derived((innerWidth.current || 1024) < 768);302const scrolled = $derived((scrollY.current || 0) > 0);303const isOnline = $derived(online.current ?? true); // Default to online304```305306## Types307308```typescript { .api }309interface ReactiveValue<T> {310get current(): T;311}312```313314## Best Practices3153161. **Handle undefined values**: Always provide fallbacks for server-side rendering3172. **Debounce expensive operations**: Window events can fire frequently3183. **Use for responsive design**: Perfect for JavaScript-based responsive behavior3194. **Combine with CSS**: Use alongside CSS media queries for complete responsive design3205. **Consider performance**: Some values update in `requestAnimationFrame` loops3216. **Test across browsers**: `devicePixelRatio` behavior varies between browsers322323## Common Patterns324325### Responsive Breakpoints326327```typescript328import { innerWidth } from "svelte/reactivity/window";329330const breakpoints = {331sm: 640,332md: 768,333lg: 1024,334xl: 1280335};336337const screen = $derived(() => {338const width = innerWidth.current || 1024;339340if (width >= breakpoints.xl) return "xl";341if (width >= breakpoints.lg) return "lg";342if (width >= breakpoints.md) return "md";343if (width >= breakpoints.sm) return "sm";344return "xs";345});346```347348### Scroll-Based Navigation349350```typescript351import { scrollY } from "svelte/reactivity/window";352353let sections = [];354let activeSection = $state(0);355356$effect(() => {357const currentScroll = scrollY.current || 0;358359// Find active section based on scroll position360const active = sections.findIndex((section, index) => {361const nextSection = sections[index + 1];362const sectionTop = section.offsetTop;363const sectionBottom = nextSection ? nextSection.offsetTop : document.body.scrollHeight;364365return currentScroll >= sectionTop - 100 && currentScroll < sectionBottom - 100;366});367368if (active !== -1) {369activeSection = active;370}371});372```