├── src ├── vite-env.d.ts ├── constants.ts ├── index.tsx └── useScreenSize.tsx ├── tsconfig.json ├── .gitignore ├── postinstall.js ├── tsconfig.build.json ├── vite.config.ts ├── tsconfig.node.json ├── tsconfig.app.json ├── eslint.config.js ├── LICENSE ├── .github └── workflows │ └── ci.yml ├── package.json └── README.md /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" }, 6 | { "path": "./tsconfig.build.json" } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | // constants.ts 2 | export const BreakPoint = { 3 | xs: 'xs', 4 | s: 's', 5 | m: 'm', 6 | l: 'l', 7 | xl: 'xl', 8 | } as const; 9 | 10 | export type BreakPoint = typeof BreakPoint[keyof typeof BreakPoint]; 11 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | export { useScreenSize, DEFAULT_BREAKPOINTS } from './useScreenSize'; 2 | export type { ScreenSize, BreakPointConfig } from './useScreenSize'; 3 | export { BreakPoint } from './constants'; // Runtime export 4 | export type { BreakPoint as BreakPointType } from './constants'; // Type-only export 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /postinstall.js: -------------------------------------------------------------------------------- 1 | // ANSI escape codes for styling 2 | const reset = '\x1b[0m'; 3 | const bright = '\x1b[1m'; 4 | const fgGreen = '\x1b[32m'; 5 | const fgCyan = '\x1b[36m'; 6 | const fgMagenta = '\x1b[35m'; 7 | 8 | console.log(` 9 | ${fgGreen}${bright}Thank you for installing use-screen-size!${reset} 10 | ${fgCyan}If you find this package helpful, please consider starring our GitHub repository:${reset} 11 | ${fgMagenta}https://github.com/kingflamez/use-screen-size${reset} 12 | `); 13 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "declarationDir": "./dist/types", 5 | "emitDeclarationOnly": true, 6 | "outDir": "./dist", 7 | "target": "ES2020", 8 | "module": "ESNext", 9 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 10 | "moduleResolution": "Node", 11 | "jsx": "react-jsx", 12 | "strict": true, 13 | "esModuleInterop": true, 14 | "skipLibCheck": true, 15 | "allowSyntheticDefaultImports": true 16 | }, 17 | "include": ["src"], 18 | "exclude": ["node_modules", "dist"] 19 | } 20 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | import path from 'path'; 4 | 5 | export default defineConfig({ 6 | plugins: [react()], 7 | build: { 8 | lib: { 9 | entry: path.resolve(__dirname, 'src/index.tsx'), 10 | name: 'useScreenSize', 11 | fileName: (format) => `use-screen-size.${format}.js`, 12 | formats: ['es', 'umd'], 13 | }, 14 | rollupOptions: { 15 | external: ['react', 'react-dom'], 16 | output: { 17 | dir: 'dist', 18 | globals: { 19 | react: 'React', 20 | 'react-dom': 'ReactDOM', 21 | }, 22 | }, 23 | }, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | "types": ["node"], 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | "strict": true, 15 | "noUnusedLocals": true, 16 | "noUnusedParameters": true, 17 | "noFallthroughCasesInSwitch": true, 18 | "noUncheckedSideEffectImports": true, 19 | "esModuleInterop": true, 20 | "allowSyntheticDefaultImports": true 21 | }, 22 | "include": ["vite.config.ts"] 23 | } 24 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 | "target": "ES2020", 5 | "useDefineForClassFields": true, 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "isolatedModules": true, 14 | "moduleDetection": "force", 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noUncheckedSideEffectImports": true 24 | }, 25 | "include": ["src"] 26 | } 27 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import globals from 'globals' 3 | import reactHooks from 'eslint-plugin-react-hooks' 4 | import reactRefresh from 'eslint-plugin-react-refresh' 5 | import tseslint from 'typescript-eslint' 6 | 7 | export default tseslint.config( 8 | { ignores: ['dist'] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ['**/*.{ts,tsx}'], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | 'react-hooks': reactHooks, 18 | 'react-refresh': reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | 'react-refresh/only-export-components': [ 23 | 'warn', 24 | { allowConstantExport: true }, 25 | ], 26 | }, 27 | }, 28 | ) 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 use-screen-size 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Publish Package to npm 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | with: 13 | token: ${{ secrets.GITHUB_TOKEN }} 14 | ref: ${{ github.event.repository.default_branch }} # Checkout the default branch 15 | 16 | - name: Setup Node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: '20.x' 20 | registry-url: 'https://registry.npmjs.org' 21 | 22 | - name: Install dependencies 23 | run: npm ci 24 | 25 | - name: Build 26 | run: npm run build 27 | 28 | - name: Update package.json with release tag 29 | run: | 30 | TAG=${GITHUB_REF#refs/tags/} 31 | echo "Updating package.json version to $TAG" 32 | npm version $TAG --no-git-tag-version 33 | 34 | - name: Commit and push version update 35 | run: | 36 | git config user.name "github-actions" 37 | git config user.email "github-actions@github.com" 38 | git add package.json package-lock.json 39 | git commit -m "Update package.json to version $TAG" 40 | git push origin ${{ github.event.repository.default_branch }} 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | 44 | - name: Fix pkg 45 | run: npm pkg fix 46 | 47 | - name: Publish to npm 48 | run: npm publish --access public 49 | env: 50 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "use-screen-size", 3 | "version": "1.4.11", 4 | "description": "A React hook to get the current screen size and breakpoint or write conditional code based on screen size", 5 | "main": "dist/use-screen-size.umd.js", 6 | "module": "dist/use-screen-size.es.js", 7 | "types": "dist/types/index.d.ts", 8 | "files": [ 9 | "postinstall.js", 10 | "dist" 11 | ], 12 | "type": "module", 13 | "scripts": { 14 | "dev": "vite", 15 | "clean": "rimraf dist", 16 | "build": "npm run clean && vite build && tsc -p tsconfig.build.json", 17 | "postinstall": "if [ -f ./postinstall.js ]; then node postinstall.js; else echo 'postinstall.js not found'; fi", 18 | "lint": "eslint .", 19 | "preview": "vite preview" 20 | }, 21 | "keywords": [ 22 | "react", 23 | "hook", 24 | "screen-size", 25 | "breakpoints", 26 | "responsive" 27 | ], 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/kingflamez/use-screen-size.git" 31 | }, 32 | "peerDependencies": { 33 | "react": ">=16.8.0 <19.0.0", 34 | "react-dom": ">=16.8.0 <19.0.0" 35 | }, 36 | "author": "@kingflamez", 37 | "license": "MIT", 38 | "publishConfig": { 39 | "registry": "https://registry.npmjs.org/" 40 | }, 41 | "devDependencies": { 42 | "@eslint/js": "^9.15.0", 43 | "@types/node": "^22.10.1", 44 | "@types/react": "^18.3.12", 45 | "@types/react-dom": "^18.3.1", 46 | "@vitejs/plugin-react": "^4.3.4", 47 | "eslint": "^9.15.0", 48 | "eslint-plugin-react-hooks": "^5.0.0", 49 | "eslint-plugin-react-refresh": "^0.4.14", 50 | "globals": "^15.12.0", 51 | "react": "^18.0.0", 52 | "react-dom": "^18.0.0", 53 | "rimraf": "^6.0.1", 54 | "typescript": "~5.6.2", 55 | "vite": "^6.0.1" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/useScreenSize.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback, useMemo } from "react"; 2 | import { BreakPoint } from "./constants"; 3 | 4 | export interface ScreenSize { 5 | width: number; 6 | height: number; 7 | screen: BreakPoint; 8 | } 9 | 10 | export interface BreakPointConfig { 11 | xs: number; 12 | s: number; 13 | m: number; 14 | l: number; 15 | xl: number; 16 | } 17 | 18 | export const DEFAULT_BREAKPOINTS: BreakPointConfig = { 19 | xs: 576, 20 | s: 768, 21 | m: 992, 22 | l: 1200, 23 | xl: Infinity, 24 | }; 25 | 26 | export const useScreenSize = ( 27 | breakpoints: BreakPointConfig = DEFAULT_BREAKPOINTS, 28 | debounceMs = 250 29 | ): ScreenSize => { 30 | const isClient = typeof window !== "undefined" && window !== null; 31 | 32 | const getSize = useCallback((): ScreenSize => { 33 | const width = isClient ? window.innerWidth : 0; 34 | const height = isClient ? window.innerHeight : 0; 35 | 36 | let screen: BreakPoint = BreakPoint.xl; 37 | if (width < breakpoints.xs) screen = BreakPoint.xs; 38 | else if (width < breakpoints.s) screen = BreakPoint.s; 39 | else if (width < breakpoints.m) screen = BreakPoint.m; 40 | else if (width < breakpoints.l) screen = BreakPoint.l; 41 | 42 | return { width, height, screen }; 43 | }, [isClient, breakpoints]); 44 | 45 | const [screenSize, setScreenSize] = useState(getSize); 46 | 47 | useEffect(() => { 48 | if (!isClient) { 49 | return; 50 | } 51 | 52 | let timeoutId: NodeJS.Timeout; 53 | 54 | function handleResize(): void { 55 | clearTimeout(timeoutId); 56 | timeoutId = setTimeout(() => { 57 | setScreenSize(getSize()); 58 | }, debounceMs); 59 | } 60 | 61 | window.addEventListener("resize", handleResize); 62 | return (): void => { 63 | window.removeEventListener("resize", handleResize); 64 | clearTimeout(timeoutId); 65 | }; 66 | }, [isClient, getSize, debounceMs]); 67 | 68 | const screen = useMemo(() => { 69 | const { width } = screenSize; 70 | if (width < breakpoints.xs) return BreakPoint.xs; 71 | if (width < breakpoints.s) return BreakPoint.s; 72 | if (width < breakpoints.m) return BreakPoint.m; 73 | if (width < breakpoints.l) return BreakPoint.l; 74 | return BreakPoint.xl; 75 | }, [screenSize, breakpoints]); 76 | 77 | return { 78 | ...screenSize, 79 | screen, 80 | }; 81 | }; 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # use-screen-size 2 | 3 | > This helps you write conditional code based on screen size, or get the screen size value 4 | 5 | [![NPM](https://img.shields.io/npm/v/use-screen-size.svg)](https://www.npmjs.com/package/use-screen-size) 6 | [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) 7 | [![NPM](https://img.shields.io/npm/dm/use-screen-size.svg)](https://www.npmjs.com/package/use-screen-size) 8 | ![Total Downloads](https://img.shields.io/npm/dt/use-screen-size) 9 | 10 | 11 | 12 | ## Install 13 | 14 | ```bash 15 | npm install --save use-screen-size 16 | ``` 17 | 18 | ```bash 19 | yarn add use-screen-size 20 | ``` 21 | 22 | ## Example 23 | 24 | > This shows a quick example of displaying your screen width, screen height and current screen mode 25 | 26 | ```tsx 27 | import React from 'react'; 28 | 29 | import { useScreenSize } from 'use-screen-size'; 30 | 31 | const App = () => { 32 | const size = useScreenSize(); 33 | 34 | return ( 35 | <> 36 |

37 | {size.width}px / {size.height}px 38 |

39 |

{size.screen}

40 | 41 | ); 42 | }; 43 | ``` 44 | 45 | ## Helpful Methods 46 | 47 | 1. `size.screen` is used to get the quick current size mode of the screen 48 | 49 | | Name | Size | property | 50 | | ----------- | ------- | -------- | 51 | | Extra small | <576px | xs | 52 | | Small | ≥576px | s | 53 | | Medium | ≥768px | m | 54 | | Large | ≥992px | l | 55 | | Large | ≥1200px | xl | 56 | 57 | 2. `size.width` its is used to get the width of the screen in pixels 58 | 59 | 3. `size.height` its is used to get the height of the screen in pixels 60 | 61 | ## Advanced Example 62 | 63 | > This shows an advanced example of running conditional actions based on the screen size 64 | 65 | ```tsx 66 | import React, { useState, useEffect } from 'react'; 67 | 68 | import { BreakPoint, useScreenSize } from 'use-screen-size'; 69 | 70 | const App = () => { 71 | const size = useScreenSize(); 72 | const [color, setColor] = useState(''); 73 | const [screenSize, setScreenSize] = useState(''); 74 | 75 | useEffect(() => { 76 | if (size.screen == BreakPoint.xs) { 77 | setColor('red'); 78 | setScreenSize('Extra Small Screen eg Mobile Phones(Portrait Mode)'); 79 | } else if (size.screen === BreakPoint.s) { 80 | setColor('blue'); 81 | setScreenSize('Small Screen eg Mobile Phones(Landscape Mode)'); 82 | } else if (size.screen === BreakPoint.m) { 83 | setColor('orange'); 84 | setScreenSize('Medium Screen eg Tablet'); 85 | } else if (size.screen === BreakPoint.l) { 86 | setColor('yellowgreen'); 87 | setScreenSize('Large Screen eg Laptop, PC'); 88 | } else if (size.screen === BreakPoint.xl) { 89 | setColor('darkmagenta'); 90 | setScreenSize('Extra Large Screen eg Laptop, PC'); 91 | } 92 | }, [size]); 93 | 94 | return ( 95 | <> 96 |

97 | {size.width}px / {size.height}px 98 |

99 |

100 | {size.screen.toUpperCase()} {screenSize} 101 |

102 | 103 | ); 104 | }; 105 | ``` 106 | 107 | ## Configuration Options 108 | 109 | The hook accepts the following configuration options: 110 | 111 | | Option | Type | Default | Description | 112 | | ------------- | ------------------ | ---------------------------------------------------- | ------------------------------------------------ | 113 | | `breakpoints` | `BreakPointConfig` | `{ xs: 576, s: 768, m: 992, l: 1200, xl: Infinity }` | Define custom screen size breakpoints. | 114 | | `debounceMs` | `number` | `250` | Debounce time in milliseconds for resize events. | 115 | 116 | Example: 117 | 118 | ```tsx 119 | const breakpoints = { 120 | xs: 500, 121 | s: 700, 122 | m: 900, 123 | l: 1100, 124 | xl: Infinity 125 | } 126 | 127 | const size = useScreenSize(breakpoints, 300) // Custom breakpoints and debounce time 128 | ``` 129 | 130 | ## License 131 | 132 | Follow on Twitter [@__wole__](https://twitter.com/__wole__) 133 | 134 | MIT © [kingflamez](https://github.com/kingflamez) 135 | --------------------------------------------------------------------------------