@werk1/w1-system-device-info
v2.1.3
Published
W1 System Device Info Detection Package - Performance Optimized
Maintainers
Readme
@werk1/w1-system-device-info
Advanced device detection and responsive state management for React applications - Performance Optimized v1.3.0
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-infoPeer Dependencies:
react >= 16.8.0zustand >= 4.0.0
🚀 Quick Start
Installation
npm install @werk1/w1-system-device-infoBasic 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 LandscapeDevice 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 completeDevice 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'
- Tablet Portrait →
deviceStyleSuffix: With tablet→desktop mapping for CSS reuse- Tablet Portrait →
'DS'(mapped to Desktop Small styles) - Tablet Landscape →
'DL'(mapped to Desktop Large styles)
- Tablet Portrait →
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
- Integration Guide - Detailed integration options
- API Reference - Complete API documentation
- Examples - More usage examples
🎯 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.
