CSS custom property bridge
Breakpoints are written as @media rules that set --viewport on :root. JavaScript reads back the current state with a single getComputedStyle call instead of duplicating logic in both languages.
01 · Why it exists
Responsive JavaScript logic is a recurring pain point. window.innerWidth checks scatter magic numbers everywhere. matchMedia() listeners require a separate handler per breakpoint. Importing SCSS variables into JS tightly couples your build. Polling with a resize observer still means defining breakpoints twice.
getViewport takes a different approach: pass a plain JS object once, and it auto-generates the @media rules, injects them at runtime, and reads the active breakpoint back via getComputedStyle. One source of truth, no duplication, no polling.
Core behavior
Breakpoints are written as @media rules that set --viewport on :root. JavaScript reads back the current state with a single getComputedStyle call instead of duplicating logic in both languages.
On resize, internal state updates immediately so the UI reacts fast, then settles after 100 ms. Both immediate accuracy and stable final values, without writing your own debounce.
Ships with standard Bootstrap 5 breakpoints (xs through xxl) out of the box. Pass any custom object to override with Tailwind, Material, or your own system.
02 · Installation
npm / yarn
npm install get-viewport
// CommonJS
const getViewport = require('get-viewport');
// ESM
import getViewport from 'get-viewport';
CDN
<script src="https://unpkg.com/get-viewport/getViewport.js"></script>
<!-- window.getViewport is now available -->
03 · How it works
When you call new getViewport(), it generates one @media rule per breakpoint and injects them into a <style> tag. Each rule sets the custom property encoding the current breakpoint name and index.
@media (min-width: 0px) { :root { --viewport: 'xs,1'; } }
@media (min-width: 576px) { :root { --viewport: 'sm,2'; } }
@media (min-width: 768px) { :root { --viewport: 'md,3'; } }
@media (min-width: 992px) { :root { --viewport: 'lg,4'; } }
@media (min-width: 1200px) { :root { --viewport: 'xl,5'; } }
@media (min-width: 1400px) { :root { --viewport: 'xxl,6'; } }
CSS cascade ensures the variable always reflects the current breakpoint. A dual-source verification step cross-checks against window.innerWidth for edge cases during rapid resizes.
04 · API reference
| Method | Returns | Description |
|---|---|---|
getBreakpoint() | 'md' | Current breakpoint name |
getBreakpointValue() | 3 | Numeric index (1-based, smallest to largest) |
isMobile() | boolean | Value 2 or lower (xs, sm) |
isTablet() | boolean | Value exactly 3 (md) |
isDesktop() | boolean | Value above 3 (lg and wider) |
getWidth() | 1280 | Current window.innerWidth in px |
getHeight() | 800 | Current window.innerHeight in px |
getDimensions() | {width, height} | Both dimensions as an object |
getBreakpoints() | {xs: 0, …} | Copy of active breakpoint definitions |
05 · Usage examples
Basic usage
const viewport = new getViewport();
console.log(viewport.getBreakpoint()); // 'lg'
console.log(viewport.getBreakpointValue()); // 4
console.log(viewport.isMobile()); // false
console.log(viewport.getDimensions()); // { width: 1024, height: 768 }
Resize handling
window.addEventListener('resize', () => {
if (viewport.isMobile()) {
collapseNavigation();
} else {
expandNavigation();
}
});
Custom Tailwind-style breakpoints
const viewport = new getViewport({
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
'2xl': 1536,
});
MIT licensed. Source, issues, and pull requests welcome on GitHub.
Keep exploring