├── 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 | [](https://www.npmjs.com/package/use-screen-size)
6 | [](https://standardjs.com)
7 | [](https://www.npmjs.com/package/use-screen-size)
8 | 
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 |
--------------------------------------------------------------------------------