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 🙏

© 2025 – Pkg Stats / Ryan Hefner

force-portrait-mode

v1.2.1

Published

Lightweight library to enforce portrait orientation on mobile devices with customizable animations and messages

Readme

force-portrait-mode

npm version Build Status Coverage Status MIT License TypeScript

A lightweight, customizable library that enforces portrait orientation on mobile devices with smooth user experience and professional animations.

✨ Features

  • 🎨 Fully Customizable - Colors, icons, messages, animations, and positioning
  • 📱 Mobile-First - Optimized for all mobile browsers and devices
  • Ultra-Lightweight - < 1KB gzipped, zero dependencies
  • 🔧 Framework Agnostic - Works with React, Vue, Angular, vanilla JS
  • 🎯 TypeScript Ready - Full type definitions included
  • Accessible - Respects user motion preferences and ARIA standards
  • 🌐 CSS-Only Option - Pure CSS solution available (no JavaScript required)
  • 📊 Smart Positioning - Automatic overlap prevention and responsive sizing
  • 🎭 Built-in Themes - Dark, light, neon, and minimal themes included

🚀 Quick Start

Installation

npm install force-portrait-mode
yarn add force-portrait-mode

Basic Usage

import { enablePortraitMode } from 'force-portrait-mode'

// Enable with default settings (40% icon, 70% text positioning)
enablePortraitMode()

// Or with custom options
enablePortraitMode({
  backgroundColor: '#1a1a1a',
  icon: '📲',
  message: 'Please rotate your device to portrait mode',
  theme: 'dark'
})

CSS-Only Usage

<!-- Include the CSS file -->
<link rel="stylesheet" href="node_modules/force-portrait-mode/styles/force-portrait.min.css">

<!-- Or use a CDN -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/styles/force-portrait.min.css">

📖 Usage Examples

Vanilla JavaScript

import { enablePortraitMode, disablePortraitMode } from 'force-portrait-mode'

// Basic usage
const cleanup = enablePortraitMode({
  backgroundColor: '#000000',
  textColor: '#ffffff',
  icon: '📱',
  message: 'Rotate your phone for better experience'
})

// Clean up when needed
// cleanup()

React Integration

import { enablePortraitMode } from 'force-portrait-mode'
import { useEffect } from 'react'

function App() {
  useEffect(() => {
    const cleanup = enablePortraitMode({
      backgroundColor: '#2d3748',
      textColor: '#e2e8f0',
      icon: '📲',
      theme: 'dark'
    })
    
    return cleanup
  }, [])
  
  return (
    <div className="app">
      <h1>My Mobile App</h1>
      <p>Content optimized for portrait mode</p>
    </div>
  )
}

Vue 3 Integration

<script setup>
import { enablePortraitMode } from 'force-portrait-mode'
import { onMounted, onUnmounted } from 'vue'

let cleanup = null

onMounted(() => {
  cleanup = enablePortraitMode({
    backgroundColor: '#1a1a1a',
    icon: '🎮',
    message: 'Game works best in portrait mode',
    animation: {
      type: 'bounce',
      duration: '1.5s'
    }
  })
})

onUnmounted(() => {
  if (cleanup) cleanup()
})
</script>

<template>
  <div class="game-app">
    <h1>Mobile Game</h1>
    <!-- Your game content -->
  </div>
</template>

TypeScript

import { 
  enablePortraitMode, 
  PortraitModeOptions,
  ThemePreset 
} from 'force-portrait-mode'

const config: PortraitModeOptions = {
  backgroundColor: '#1a1a1a',
  textColor: '#ffffff',
  icon: '📱',
  iconSize: '4rem',
  fontSize: '1.2rem',
  iconPosition: { top: '35%' },
  textPosition: { top: '65%' },
  animation: {
    enabled: true,
    type: 'rotate',
    duration: '2s'
  },
  onShow: () => console.log('Portrait mode activated'),
  onHide: () => console.log('Portrait mode deactivated')
}

const result = enablePortraitMode(config)
console.log('Layout adjusted:', result.layout.adjusted)

🎨 Customization Options

Basic Configuration

enablePortraitMode({
  // Visual customization
  backgroundColor: '#000000',      // Background color
  textColor: '#ffffff',           // Text color  
  icon: '📱',                     // Icon/emoji to display
  iconColor: '#4CAF50',          // Icon color (optional)
  message: 'Custom message',      // Text message
  
  // Typography
  fontFamily: 'Arial, sans-serif',
  fontSize: '1.2rem',             // Responsive: { min: '0.9rem', max: '1.2rem', viewport: '4vw' }
  fontWeight: '600',
  iconSize: '4rem',               // Responsive sizing supported
  
  // Positioning (default: icon 40%, text 70%)
  iconPosition: { top: '40%', left: '50%' },
  textPosition: { top: '70%', left: '50%' },
  
  // Animation
  animation: {
    enabled: true,
    type: 'rotate',               // 'rotate', 'bounce', 'pulse', 'shake'
    duration: '2s',
    rotationAngle: 15
  }
})

Advanced Configuration

enablePortraitMode({
  // Layout control
  layout: {
    preventOverlap: true,         // Automatic overlap prevention
    responsive: true,             // Responsive sizing
    minSpacing: '2rem',          // Minimum space between elements
    fallbackLayout: 'vertical-stack'
  },
  
  // Text handling
  textHandling: {
    maxWidth: '90vw',            // Prevent text overflow
    truncate: true,              // Add ellipsis for long text
    multiLine: false,            // Force single line
    breakWords: false            // Prevent word breaking
  },
  
  // Behavior
  zIndex: 9999,                  // CSS z-index
  overlay: true,                 // Show background overlay
  blur: false,                   // Backdrop blur effect
  hideScrollbar: true,           // Hide scrollbars in landscape
  preventScroll: true,           // Prevent scrolling
  
  // Accessibility
  ariaLabel: 'Rotate device',    // Screen reader label
  respectPrefers: true,          // Respect prefers-reduced-motion
  
  // Callbacks
  onShow: () => console.log('Landscape detected'),
  onHide: () => console.log('Portrait restored')
})

🎭 Built-in Themes

Using Preset Themes

// Dark theme (default)
enablePortraitMode({ theme: 'dark' })

// Light theme
enablePortraitMode({ theme: 'light' })

// Neon theme
enablePortraitMode({ theme: 'neon' })

// Minimal theme
enablePortraitMode({ theme: 'minimal' })

Custom Themes

// Custom theme object
enablePortraitMode({
  theme: {
    backgroundColor: '#ff6b6b',
    textColor: 'white',
    icon: '⚡',
    iconColor: '#ffd93d',
    animation: 'bounce'
  }
})

CSS-Only Themes

/* Apply theme class to body */
body.force-portrait-theme-neon {
  --portrait-bg-color: rgba(0, 0, 0, 0.9);
  --portrait-text-color: #00ff88;
  --portrait-icon-color: #ff0080;
  --portrait-icon: '📲';
}

🔧 API Reference

Functions

enablePortraitMode(options?)

Enables portrait mode enforcement with optional configuration.

Parameters:

  • options (optional): PortraitModeOptions - Configuration object

Returns:

  • PortraitModeResult - Object with cleanup function and layout info

disablePortraitMode()

Disables portrait mode enforcement and cleans up resources.

updatePortraitMode(options)

Updates current portrait mode configuration dynamically.

getPortraitModeState()

Returns current state information.

CSS-Only Usage

Include the CSS file and optionally customize with CSS custom properties:

:root {
  --portrait-bg-color: rgba(0, 0, 0, 0.9);
  --portrait-text-color: #ffffff;
  --portrait-icon: '📱';
  --portrait-message: 'Please rotate your device';
  --portrait-icon-top: 40%;      /* Icon position */
  --portrait-text-top: 70%;      /* Text position */
}

🌍 Browser Compatibility

  • iOS Safari - Full support
  • Android Chrome - Full support
  • Android Firefox - Full support
  • WebView containers (Telegram WebApp, etc.)
  • Progressive Web Apps (PWA)
  • All modern mobile browsers

📱 Framework Integration

Installation

npm install force-portrait-mode

The library provides a framework-agnostic core that works with any JavaScript framework. Simply import the core functions and integrate them into your framework's lifecycle methods as shown in the examples above.

🎯 Default Positioning

The library uses optimized default positioning for mobile devices:

  • Icon: 40% from top (optimal visibility)
  • Text: 70% from top (comfortable reading position)
  • Automatic adjustment for small screens to prevent overlap

⚡ Performance

  • Ultra-Lightweight: < 1KB gzipped (21KB core)
  • Zero dependencies: No external libraries required
  • Optimized build: Tree-shaken with aggressive compression
  • CSS-only option: Pure CSS solution available
  • GPU accelerated: Smooth animations using transform
  • Memory efficient: Automatic cleanup and resource management

🔒 Security

  • No external dependencies
  • No data collection or analytics
  • No network requests
  • CSP (Content Security Policy) friendly
  • Open source and auditable

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

git clone https://github.com/sai-na/force-portrait-mode.git
cd force-portrait-mode
npm install
npm run dev

Running Tests

npm test              # Run tests
npm run test:watch    # Watch mode
npm run test:coverage # With coverage

📄 License

MIT © SAI NATH


🔗 Links