Vue Screen Utilities
vue-screen-utils is a dependency-free Vue 3 library providing a suite of reactive utility functions for managing screen breakpoints, media queries, DOM element resize observations, and dark mode detection. Currently in version `1.0.0-beta.13`, it is in active development with a stable `1.0.0` release anticipated soon, implying a potentially frequent update cadence until then. The library is fully written in TypeScript, offering robust type safety and excellent IDE support. It distinguishes itself by allowing developers to define custom, semantically named screen size keys (e.g., `sm`, `md`, `lg`) and map them to various media query formats, which are then reactively evaluated against the current viewport. It offers both composable functions like `useScreens`, `useMediaQuery`, `useResizeObserver`, and `useDarkMode`, as well as a plugin for application-wide integration. Key features include a reactive `matches` object indicating active breakpoints, a `current` computed property for the largest active screen key, and utility functions like `mapCurrent` and `mapList` for mapping custom values to the current screen state.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'value') or (reading 'md')
cause Attempting to access properties like `.current.value` or `.matches.md` on the `$screens` object when it is `undefined` because `inject('$screens')` failed.fixEnsure `useScreens()` is called in an ancestor component. Add a check for `$screens` being `null` or `undefined` after `inject()` to handle cases where it might not be provided, e.g., `const currentScreen = computed(() => $screens?.current.value || 'default');` -
Module not found: Error: Can't resolve 'vue-screen-utils' in '...'
cause The `vue-screen-utils` package has not been installed or there's a typo in the import path.fixRun `npm install vue-screen-utils` or `yarn add vue-screen-utils`. Double-check the import statement for typos. -
Argument of type '{ min: string; }' is not assignable to parameter of type 'string | string[] | Record<string, string | MediaValue | MediaValue[]>'.cause Incorrect format or type provided in the configuration object to `useScreens` when defining custom screen breakpoints, particularly with TypeScript.fixRefer to the `useScreens` documentation for the correct `config` object format, ensuring that values are `string`, `string[]`, `{ min: string }`, `{ max: string }`, or arrays of these, matching the `MediaValue` type definition.
Warnings
- breaking As of version `1.0.0-beta.13`, the library is still in beta. While APIs are generally stable, minor breaking changes might occur before the official 1.0.0 stable release. Always review release notes when upgrading between beta versions.
- gotcha When defining screen sizes with `useScreens`, it is strongly recommended to order them from smallest to largest (e.g., `xs: '0px'`, `sm: '640px'`, `md: '768px'`). The internal logic often relies on this order for determining the 'current' active screen.
- gotcha To use the `inject('$screens')` method in a child component, an ancestor component (typically a root or parent) must first call `useScreens()` to provide the screen utilities. If `useScreens` is not called, `inject('$screens')` will return `undefined`.
- gotcha By default, `useScreens` injects its utilities using the key `'$screens'`. If you specify a custom `injectKey` in the `useScreens` options (e.g., `{ injectKey: '$myScreens' }`), child components must use the exact same custom key when calling `inject()`.
Install
-
npm install vue-screen-utils -
yarn add vue-screen-utils -
pnpm add vue-screen-utils
Imports
- useScreens
const { useScreens } = require('vue-screen-utils')import { useScreens } from 'vue-screen-utils' - inject
import { inject } from 'vue' - Screens
import type { Screens } from 'vue-screen-utils'
Quickstart
// App.vue (Parent component where screens are configured)
<script setup lang="ts">
import { useScreens } from 'vue-screen-utils';
import ChildComponent from './ChildComponent.vue'; // Assume this file exists and is imported
// Configure screen breakpoints. This call also automatically 'provides' the screen utilities
// under the key '$screens' (or a custom injectKey if specified).
useScreens({
xs: '0px', // Example: (min-width: 0px)
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px'
});
</script>
<template>
<div style="font-family: sans-serif; padding: 20px;">
<h1>Parent Component</h1>
<p>This component sets up the global screen utilities.</p>
<ChildComponent />
</div>
</template>
// ChildComponent.vue (Child component accessing screen utilities)
<script setup lang="ts">
import { inject, computed } from 'vue';
import type { Screens } from 'vue-screen-utils';
// Inject the screens object that was provided by the parent via useScreens.
// Type assertion `!` can be used if you're certain it will be injected, or handle `null`.
const $screens = inject<Screens>('$screens');
// Defensive check for robustness, especially in complex applications
if (!$screens) {
console.error("Screen utilities not injected. Ensure useScreens is called in an ancestor.");
// In a real application, you might provide fallback values or throw an error.
}
// Access reactive screen properties and utility functions
const currentScreen = computed(() => $screens?.current.value || 'N/A');
const isLargeScreen = computed(() => $screens?.matches.lg || false);
const mappedValue = computed(() =>
$screens?.mapCurrent({ xs: 0, sm: 1, md: 2, lg: 3, xl: 4 }, 0).value || 0
);
</script>
<template>
<div style="border: 1px solid #ccc; padding: 15px; margin-top: 20px;">
<h2>Child Component</h2>
<p>Resize your browser window to see reactive updates:</p>
<p>Current screen: <strong>{{ currentScreen }}</strong></p>
<p>Is 'large' (>=1024px): <strong>{{ isLargeScreen }}</strong></p>
<p>Mapped value for current screen: <strong>{{ mappedValue }}</strong></p>
<p v-if="currentScreen === 'xl'" style="color: #007bff;">You're on an extra-large screen!</p>
</div>
</template>