npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@werk1/w1-system-device-info

v2.1.3

Published

W1 System Device Info Detection Package - Performance Optimized

Readme

@werk1/w1-system-device-info

Advanced device detection and responsive state management for React applications - Performance Optimized v1.3.0

npm version npm downloads TypeScript

A lightweight, TypeScript-first device detection library that provides comprehensive device information and responsive states for React applications. Built with Zustand for optimal performance and flexibility.

✨ Features

  • 🎯 Comprehensive Device Detection - Desktop, tablet, phone, and mobile detection
  • 📱 Orientation Support - Portrait and landscape detection with position states
  • 🎨 Responsive States - Ready-to-use boolean states for responsive design
  • 🔧 Flexible Integration - Use standalone or integrate with existing Zustand stores
  • 💎 TypeScript First - Full type safety and IntelliSense support
  • Zero Dependencies - Only peer dependencies on React and Zustand
  • 🎭 SSR Compatible - Works with Next.js and other SSR frameworks
  • 🔄 Smart Updates - Responds to meaningful resize and orientation changes only
  • 📏 Stable Device Dimensions - Separate tracking of device vs viewport dimensions (v1.4.0+)

🚀 Performance Improvements (v1.3.0)

Before (v1.2.x): Performance Issues

  • ❌ Updated on every resize event (hundreds per second during scroll)
  • ❌ Expensive UA parsing on each update
  • ❌ No change detection - always updated entire state
  • ❌ Caused ScrollTrigger instability and animation jitter

After (v1.3.0): Optimized Performance

  • Throttled updates - Maximum 150ms intervals (configurable)
  • Smart change detection - Only updates for significant dimension changes (10px+ threshold)
  • Cached UA parsing - Device agent info calculated once and cached
  • Separated concerns - Stable vs dynamic properties for selective subscriptions
  • ScrollTrigger friendly - No more animation jitter from excessive updates

🎯 Stable Device Dimensions (v1.4.0+)

New Feature: Separate Device and Viewport Tracking

The library now distinguishes between:

  • Device Dimensions - Stable physical device size (changes only on rotation)
  • Viewport Dimensions - Dynamic browser viewport (changes with browser UI)
// Stable device dimensions - only change on rotation
device.deviceWidth      // e.g., 390 (iPhone 14)
device.deviceHeight     // e.g., 844
device.deviceWidthInPixel   // "390px"
device.deviceHeightInPixel  // "844px"

// Dynamic viewport dimensions - change with browser UI
device.viewportWidth    // Changes when browser UI shows/hides
device.viewportHeight   // Changes during scroll on mobile
device.viewportWidthInPixel   // "390px"
device.viewportHeightInPixel  // "750px" (when browser UI is visible)

This solves the common problem where mobile browser UI changes cause unwanted layout shifts during scrolling.

📦 Installation

npm install @werk1/w1-system-device-info
# or
yarn add @werk1/w1-system-device-info
# or
pnpm add @werk1/w1-system-device-info

Peer Dependencies:

  • react >= 16.8.0
  • zustand >= 4.0.0

🚀 Quick Start

Installation

npm install @werk1/w1-system-device-info

Basic Usage (Standalone)

import { DeviceInfoTracker, useBoundStore } from '@werk1/w1-system-device-info'

function App() {
  return (
    <div>
      {/* Auto-tracking device changes */}
      <DeviceInfoTracker />
      <MyComponent />
    </div>
  )
}

function MyComponent() {
  const { device } = useBoundStore()

  return (
    <div>
      {device.is_deviceM && <MobileLayout />}
      {device.is_deviceT && <TabletLayout />}
      {device.is_deviceD && <DesktopLayout />}
    </div>
  )
}

Performance Configuration

import { DeviceInfoTracker } from '@werk1/w1-system-device-info'

function App() {
  return (
    <div>
      <DeviceInfoTracker
        boundStore={useBoundStore}
        options={{
          // Performance tuning
          throttleMs: 200,              // Throttle updates to every 200ms
          dimensionThreshold: 15,       // Only update for 15px+ changes
          enableDebugLogging: true,     // Enable performance logging

          // UI configuration
          headerLandscapePosition: 'left'
        }}
      />
      <MyApp />
    </div>
  )
}

Integration with Existing Bound Store

import { DeviceInfoTracker } from '@werk1/w1-system-device-info'
import { useBoundStore } from './your-bound-store' // Your main app store

function App() {
  return (
    <div>
      {/* Smart tracker - automatically updates YOUR bound store */}
      <DeviceInfoTracker boundStore={useBoundStore} />
      <MyComponent />
    </div>
  )
}

function MyComponent() {
  const { device } = useBoundStore() // YOUR store, not the package's store

  return (
    <div>
      {device.is_devicePL && <PhoneLandscape />}
      {device.is_deviceTLC && <TabletLandscapeCenter />}
    </div>
  )
}

Context-Based Configuration (Recommended for Large Apps)

import { DeviceInfoProvider, DeviceInfoTracker } from '@werk1/w1-system-device-info'

function App() {
  return (
    <DeviceInfoProvider
      boundStore={useBoundStore}
      options={{ headerLandscapePosition: 'left' }}
    >
      {/* Auto-detects bound store from context */}
      <DeviceInfoTracker />
      <AppLayout />
    </DeviceInfoProvider>
  )
}

📊 Available Device States

Device Types

is_deviceD    // Desktop (any desktop device)
is_deviceDS   // Desktop Small (< 800px width)
is_deviceDL   // Desktop Large (>= 800px width)

is_deviceM    // Mobile (any mobile device)
is_deviceMP   // Mobile Portrait
is_deviceML   // Mobile Landscape

is_deviceP    // Phone (any phone device)
is_devicePP   // Phone Portrait
is_devicePL   // Phone Landscape

is_deviceT    // Tablet (any tablet device)
is_deviceTP   // Tablet Portrait
is_deviceTL   // Tablet Landscape

Device Information

// Stable device dimensions (v1.4.0+)
deviceWidth          // Physical device width (changes only on rotation)
deviceHeight         // Physical device height (changes only on rotation)
deviceWidthInPixel   // Device width with 'px' unit
deviceHeightInPixel  // Device height with 'px' unit

// Dynamic viewport dimensions (v1.4.0+)
viewportWidth        // Browser viewport width (window.innerWidth)
viewportHeight       // Browser viewport height (window.innerHeight)
viewportWidthInPixel // Viewport width with 'px' unit
viewportHeightInPixel // Viewport height with 'px' unit

// Device identifier strings (v1.6.0+)
deviceIdentifier     // Raw device type: 'PP', 'PL', 'TP', 'DS', 'DL', etc.
deviceStyleSuffix    // CSS suffix with tablet→desktop mapping: 'PP', 'PL', 'DS', 'DL'

// Other device information
deviceType           // 'desktop' | 'tablet' | 'mobile'
hasTouchSupport      // Boolean - touch capability
browser              // Browser information object
os                   // Operating system information
isReady              // Boolean - detection complete

Device Identifiers for CSS (v1.6.0+)

Version 1.6.0 introduces convenient device identifier strings for CSS class names and variable names:

import { useDeviceInfo } from '@werk1/w1-system-device-info'

function MyComponent() {
  const { deviceIdentifier, deviceStyleSuffix } = useDeviceInfo()

  // Use in CSS class names
  const className = `container_device${deviceStyleSuffix}`
  // Phone Portrait: 'container_devicePP'
  // Tablet Portrait: 'container_deviceDS' (mapped to Desktop Small)

  // Use in CSS variable names
  const width = `var(--width-device${deviceStyleSuffix})`

  return <div className={className} style={{ width }} />
}

Difference between identifiers:

  • deviceIdentifier: Raw device type without mapping

    • Tablet Portrait → 'TP'
    • Tablet Landscape → 'TL'
  • deviceStyleSuffix: With tablet→desktop mapping for CSS reuse

    • Tablet Portrait → 'DS' (mapped to Desktop Small styles)
    • Tablet Landscape → 'DL' (mapped to Desktop Large styles)

This allows tablets to automatically use desktop-optimized CSS while preserving the ability to detect the actual device type when needed.


### Configuring Landscape Positioning (v2.0.0+)

Header position is now a configuration option, separate from device detection:

```tsx
import { useBoundStore } from '@werk1/w1-system-device-info'

function MyComponent() {
  const { setDeviceInfoOptions, device, deviceInfoOptions } = useBoundStore()

  // Configure landscape header position
  useEffect(() => {
    setDeviceInfoOptions({
      headerLandscapePosition: 'left' // 'center' | 'left' | 'right'
    })
  }, [])

  // Combine device state + position config
  const isLandscapeLeft = device.is_devicePL && deviceInfoOptions.headerLandscapePosition === 'left'
  const isTabletCenter = device.is_deviceTL && deviceInfoOptions.headerLandscapePosition === 'center'

  return (
    <div>
      {isLandscapeLeft && <PhoneLandscapeLeftLayout />}
      {isTabletCenter && <TabletLandscapeCenterLayout />}
    </div>
  )
}

🔧 Integration Options

For New Projects

Use the standalone approach with useDeviceInfo() for quick setup.

For Existing Apps with Zustand

Integrate the slice into your existing store for centralized state management.

For Apps without Zustand

The package includes Zustand as a peer dependency, so you can start using it immediately.

📚 Examples

Responsive Components

function ResponsiveNavigation() {
  const { is_deviceM, is_deviceD } = useDeviceInfo()

  return (
    <nav>
      {is_deviceM && <MobileMenu />}
      {is_deviceD && <DesktopMenu />}
    </nav>
  )
}

Orientation-Specific Layouts

function GalleryComponent() {
  const { is_deviceTP, is_deviceTL, is_devicePP } = useDeviceInfo()

  return (
    <div className={`
      ${is_deviceTP ? 'grid-cols-2' : ''}
      ${is_deviceTL ? 'grid-cols-4' : ''}
      ${is_devicePP ? 'grid-cols-1' : ''}
    `}>
      {/* Gallery items */}
    </div>
  )
}

Device-Specific Features

function InteractiveElement() {
  const { hasTouchSupport, is_deviceD } = useDeviceInfo()

  return (
    <button
      className={hasTouchSupport ? 'touch-friendly' : 'hover-effects'}
      onMouseEnter={is_deviceD ? handleHover : undefined}
      onTouchStart={hasTouchSupport ? handleTouch : undefined}
    >
      Click me
    </button>
  )
}

📖 Documentation

🎯 Use Cases

  • Responsive Design: Create device-specific layouts and components
  • Touch Optimization: Provide different interactions for touch vs mouse
  • Performance: Conditionally load components based on device capabilities
  • User Experience: Adapt UI patterns to device conventions
  • Analytics: Track device usage patterns

🔄 Migration from v1.0

Version 1.1+ maintains full backward compatibility. Existing useDeviceInfo() usage continues to work unchanged. New integration features are additive.

🤝 Contributing

Contributions are welcome! Please read our Contributing Guide for details.

📄 License

MIT © Werk1

🙏 Acknowledgments

Built with modern React patterns and Zustand for optimal performance and developer experience.