├── .commitlintrc.ts ├── .czrc ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── config.yml ├── pull_request_template.md └── workflows │ ├── actions │ └── setup_node-cache_dep-install_dep │ │ └── action.yml │ ├── build.yml │ ├── deploy-storybook.yml │ ├── lint.yml │ ├── npm-release.yml │ ├── test-e2e.yml │ ├── test.yml │ └── tsc.yml ├── .gitignore ├── .husky ├── commit-msg ├── pre-commit └── pre-push ├── .lintstagedrc ├── .prettierignore ├── .prettierrc ├── .storybook ├── main.ts ├── manager.ts ├── preview.tsx └── theme.ts ├── LICENSE ├── README.md ├── e2e ├── consts.ts ├── events.spec.ts ├── global.setup.ts └── on-move-params.spec.ts ├── eslint.config.mjs ├── knip.ts ├── misc ├── demo.gif └── device_orientation.jpg ├── package-lock.json ├── package.json ├── playwright.config.ts ├── scripts ├── rollup.config.ts ├── rollupConfigs.ts ├── setup-tests.ts ├── tsconfig.base.json ├── tsconfig.build.json └── tsconfig.dev.json ├── src ├── features │ ├── glare │ │ ├── Glare.ts │ │ ├── test │ │ │ ├── glare.test.tsx │ │ │ └── glareStyle.test.tsx │ │ └── types.public.ts │ └── tilt │ │ ├── Tilt.ts │ │ ├── test │ │ ├── tiltAxis.test.tsx │ │ ├── tiltDisable.test.tsx │ │ ├── tiltManualAngle.test.tsx │ │ ├── tiltMaxAngle.test.tsx │ │ ├── tiltOnEnter.test.tsx │ │ ├── tiltOnLeave.test.tsx │ │ ├── tiltOnPropChange.test.tsx │ │ ├── tiltOnTouchMove.test.tsx │ │ ├── tiltReset.test.tsx │ │ ├── tiltReverse.test.tsx │ │ ├── tiltStyle.test.tsx │ │ └── tiltTrackOnWindow.test.tsx │ │ └── types.public.ts ├── index.ts ├── react-parallax-tilt │ ├── ReactParallaxTilt.tsx │ ├── defaultProps.ts │ ├── types.public.ts │ └── types.ts └── utils │ ├── TiltTest.tsx │ ├── helperFns.ts │ └── types.ts ├── stories ├── Default │ ├── Default.demozap.tsx │ └── _Default.tsx ├── EventParams │ ├── EventParams.demozap.css │ ├── EventParams.demozap.tsx │ └── _EventParams.tsx ├── EventTiltAngle │ ├── EventTiltAngle.demozap.css │ ├── EventTiltAngle.demozap.tsx │ └── _EventTiltAngle.tsx ├── FlipPage │ ├── FlipPage.demozap.css │ ├── FlipPage.demozap.tsx │ ├── Page │ │ ├── Page.css │ │ ├── Page.tsx │ │ └── lorem-picsum.png │ └── _FlipPage.tsx ├── FlipVH │ ├── FlipVH.demozap.css │ ├── FlipVH.demozap.tsx │ └── _FlipVH.tsx ├── GlareEffect │ ├── GlareEffect.demozap.tsx │ └── _GlareEffect.tsx ├── GlareEffect360 │ ├── GlareEffect360.demozap.tsx │ └── _GlareEffect360.tsx ├── GlareEffectNoTilt │ ├── GlareEffectNoTilt.demozap.tsx │ └── _GlareEffectNoTilt.tsx ├── InitialTilt │ ├── InitialTilt.demozap.tsx │ └── _InitialTilt.tsx ├── KeepFloating │ ├── KeepFloating.demozap.tsx │ └── _KeepFloating.tsx ├── MultipleTilt │ ├── MultipleTilt.demozap.css │ ├── MultipleTilt.demozap.tsx │ └── _MultipleTilt.tsx ├── MultipleTiltScroll │ ├── MultipleTiltScroll.demozap.css │ ├── MultipleTiltScroll.demozap.tsx │ └── _MultipleTiltScroll.tsx ├── ParallaxEffect │ ├── ParallaxEffect.demozap.css │ ├── ParallaxEffect.demozap.tsx │ └── _ParallaxEffect.tsx ├── ParallaxEffectGlareScale │ ├── ParallaxEffectGlareScale.demozap.css │ ├── ParallaxEffectGlareScale.demozap.tsx │ └── _ParallaxEffectGlareScale.tsx ├── ParallaxEffectImg │ ├── ParallaxEffectImg.demozap.css │ ├── ParallaxEffectImg.demozap.tsx │ ├── _ParallaxEffectImg.tsx │ └── img │ │ ├── background.jpg │ │ └── tree.png ├── ReactParallaxTilt.css ├── ReactParallaxTilt.stories.tsx ├── ReverseTilt │ ├── ReverseTilt.demozap.tsx │ └── _ReverseTilt.tsx ├── ScaleNoTilt │ ├── ScaleNoTilt.demozap.css │ ├── ScaleNoTilt.demozap.tsx │ └── _ScaleNoTilt.tsx ├── TiltDisableAxis │ ├── TiltDisableAxis.demozap.css │ ├── TiltDisableAxis.demozap.tsx │ └── _TiltDisableAxis.tsx ├── TiltImg │ ├── TiltImg.demozap.css │ ├── TiltImg.demozap.tsx │ ├── _TiltImg.tsx │ └── img │ │ └── nyc.jpg ├── TiltManualInput │ ├── TiltManualInput.demozap.css │ ├── TiltManualInput.demozap.tsx │ └── _TiltManualInput.tsx ├── TiltScale │ ├── TiltScale.demozap.css │ ├── TiltScale.demozap.tsx │ └── _TiltScale.tsx ├── TrackOnWindow │ ├── TrackOnWindow.demozap.css │ ├── TrackOnWindow.demozap.tsx │ └── _TrackOnWindow.tsx ├── _DefaultComponent │ ├── DefaultComponent.css │ └── DefaultComponent.tsx └── types │ └── images.d.ts ├── tsconfig.json └── vitest.config.ts /.commitlintrc.ts: -------------------------------------------------------------------------------- 1 | import type { UserConfig } from '@commitlint/types'; 2 | 3 | const commitlintConfig: UserConfig = { 4 | extends: ['@commitlint/config-conventional'], 5 | }; 6 | 7 | // eslint-disable-next-line import-x/no-default-export 8 | export default commitlintConfig; 9 | -------------------------------------------------------------------------------- /.czrc: -------------------------------------------------------------------------------- 1 | { 2 | "path": "node_modules/cz-conventional-changelog" 3 | } 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 'Bug Report' 2 | description: 'File a bug report' 3 | body: 4 | - type: 'textarea' 5 | id: 'description' 6 | attributes: 7 | label: 'Description' 8 | description: 'A clear and concise description of what the bug is.' 9 | placeholder: | 10 | Bug description 11 | validations: 12 | required: true 13 | - type: 'input' 14 | id: 'reproduction_link' 15 | attributes: 16 | label: 'Link to Reproduction - Please provide demo in online code editor [CodeSandbox](https://codesandbox.io/) or similar. - Issues without a reproduction link are likely to stall.' 17 | description: | 18 | Please provide demo in online code editor [CodeSandbox](https://codesandbox.io/) or similar. 19 | Issues without a reproduction link are likely to stall. 20 | placeholder: 'https://codesandbox.io/' 21 | validations: 22 | required: true 23 | - type: 'textarea' 24 | id: 'reproduction_steps' 25 | attributes: 26 | label: 'Steps to reproduce' 27 | description: | 28 | Steps to reproduce the behavior: 29 | value: | 30 | 1. Go to '...' 31 | 2. Click on '...' 32 | 3. Scroll down to '...' 33 | 4. See error 34 | - type: 'input' 35 | id: 'expected_behavior' 36 | attributes: 37 | label: 'Expected behavior' 38 | description: 'A clear and concise description of what you expected to happen.' 39 | validations: 40 | required: true 41 | - type: 'textarea' 42 | id: 'code_snippets' 43 | attributes: 44 | label: 'Code snippets' 45 | description: | 46 | If applicable, add code samples to help explain your problem. 47 | value: | 48 | ```jsx 49 | 50 | 51 | 52 | ``` 53 | - type: 'input' 54 | id: 'lib-version' 55 | attributes: 56 | label: 'React Parallax Tilt Version' 57 | description: 'The version of library you use.' 58 | placeholder: '1.5.36' 59 | validations: 60 | required: true 61 | - type: 'input' 62 | id: 'browser' 63 | attributes: 64 | label: 'Browser' 65 | description: 'The browser this issue occurred with.' 66 | placeholder: 'Google Chrome 93' 67 | - type: 'checkboxes' 68 | id: 'operating-system' 69 | attributes: 70 | label: 'Operating System' 71 | description: 'The operating system(s) this issue occurred with.' 72 | options: 73 | - label: 'macOS' 74 | - label: 'Windows' 75 | - label: 'Linux' 76 | - type: 'textarea' 77 | id: 'additional-information' 78 | attributes: 79 | label: 'Additional Information' 80 | description: | 81 | Add any other context about the problem here. 82 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/mkosir/react-parallax-tilt/discussions 5 | about: Ask questions and discuss topics with other community members 6 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### 🚀 Pull Request Template 2 | 3 | **Description** 4 | 5 | Feature Proposal ... 6 | 7 | OR 8 | 9 | Fixes a bug where '...' happened when '...' 10 | 11 | **Checklist** 12 | 13 | - [ ] Commit messages should follow [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) as much as possible. After staging your changes please run `npm run commit` 14 | - [ ] Lint, TypeScript, Prettier and all tests passing - `npm run lint && npm run tsc && npm run test-report` 15 | - [ ] Extended the Storybook / README / documentation, if necessary 16 | -------------------------------------------------------------------------------- /.github/workflows/actions/setup_node-cache_dep-install_dep/action.yml: -------------------------------------------------------------------------------- 1 | name: 'setup_node-cache_dep-install_dep' 2 | description: 'Setup Node.js ⚙️ - Cache dependencies ⚡ - Install dependencies 🔧' 3 | runs: 4 | using: 'composite' 5 | steps: 6 | - name: Setup Node.js ⚙️ 7 | uses: actions/setup-node@v4 8 | with: 9 | node-version: '24.x' 10 | 11 | - name: Cache dependencies ⚡ 12 | id: cache_dependencies 13 | uses: actions/cache@v4 14 | with: 15 | path: node_modules 16 | key: node-modules-${{ hashFiles('package-lock.json') }} 17 | 18 | - name: Install dependencies 🔧 19 | shell: bash 20 | if: steps.cache_dependencies.outputs.cache-hit != 'true' 21 | run: npm ci 22 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: push 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout 🛎️ 11 | uses: actions/checkout@v4 12 | 13 | - name: Setup Node.js ⚙️ - Cache dependencies ⚡ - Install dependencies 🔧 14 | uses: ./.github/workflows/actions/setup_node-cache_dep-install_dep 15 | 16 | - name: Build 🏗️ 17 | run: npm run build 18 | -------------------------------------------------------------------------------- /.github/workflows/deploy-storybook.yml: -------------------------------------------------------------------------------- 1 | name: deploy-storybook 2 | 3 | on: 4 | workflow_run: 5 | workflows: [test] 6 | types: [completed] 7 | branches: [main] 8 | 9 | env: 10 | FOLDER_PATH_STORYBOOK_BUILD: ./build-storybook-static 11 | 12 | jobs: 13 | deploy-storybook: 14 | runs-on: ubuntu-latest 15 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 16 | 17 | environment: 18 | name: storybook-demos 19 | url: https://mkosir.github.io/react-parallax-tilt/?path=/story/react-parallax-tilt--event-params 20 | 21 | steps: 22 | - name: Checkout 🛎️ 23 | uses: actions/checkout@v4 24 | 25 | - name: Setup Node.js ⚙️ - Cache dependencies ⚡ - Install dependencies 🔧 26 | uses: ./.github/workflows/actions/setup_node-cache_dep-install_dep 27 | 28 | - name: Build 🏗️ 29 | run: npm run storybook-build 30 | 31 | - name: Deploy 🚀 32 | uses: JamesIves/github-pages-deploy-action@v4 33 | with: 34 | branch: gh-pages 35 | folder: ${{ env.FOLDER_PATH_STORYBOOK_BUILD }} 36 | clean: true 37 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: push 4 | 5 | jobs: 6 | lint: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout 🛎️ 11 | uses: actions/checkout@v4 12 | 13 | - name: Setup Node.js ⚙️ - Cache dependencies ⚡ - Install dependencies 🔧 14 | uses: ./.github/workflows/actions/setup_node-cache_dep-install_dep 15 | 16 | - name: Lint ✅ 17 | run: npm run lint 18 | -------------------------------------------------------------------------------- /.github/workflows/npm-release.yml: -------------------------------------------------------------------------------- 1 | name: npm-release 2 | 3 | on: 4 | workflow_run: 5 | workflows: [test] 6 | types: [completed] 7 | branches: [main] 8 | 9 | jobs: 10 | npm-release: 11 | runs-on: ubuntu-latest 12 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 13 | env: 14 | NODE_ENV: 'production' 15 | 16 | steps: 17 | - name: Checkout 🛎️ 18 | uses: actions/checkout@v4 19 | 20 | - name: Setup Node.js ⚙️ - Cache dependencies ⚡ - Install dependencies 🔧 21 | uses: ./.github/workflows/actions/setup_node-cache_dep-install_dep 22 | 23 | - name: Build 🏗️ 24 | run: npm run build 25 | 26 | - name: Release 🚀 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 30 | run: npm run release 31 | -------------------------------------------------------------------------------- /.github/workflows/test-e2e.yml: -------------------------------------------------------------------------------- 1 | name: test-e2e 2 | 3 | on: push 4 | 5 | env: 6 | FOLDER_PATH_TEST_E2E_REPORT: ./test-e2e-report 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout 🛎️ 14 | uses: actions/checkout@v4 15 | 16 | - name: Setup Node.js ⚙️ - Cache dependencies ⚡ - Install dependencies 🔧 17 | uses: ./.github/workflows/actions/setup_node-cache_dep-install_dep 18 | 19 | - name: Install Playwright Browsers 20 | run: npx playwright install --with-deps 21 | 22 | - name: Test E2E 🧪 23 | run: npx playwright test 24 | # run: npm run test-e2e 25 | 26 | - name: Upload report 📈 27 | uses: nwtgck/actions-netlify@v3 28 | # Upload test report also in case of test failure. 29 | if: always() 30 | with: 31 | publish-dir: ${{ env.FOLDER_PATH_TEST_E2E_REPORT }} 32 | production-deploy: true 33 | env: 34 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} 35 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID_TEST_E2E_REPORT }} 36 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: push 4 | 5 | env: 6 | FOLDER_PATH_TEST_UNIT_REPORT: ./test-unit-report 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout 🛎️ 14 | uses: actions/checkout@v4 15 | 16 | - name: Setup Node.js ⚙️ - Cache dependencies ⚡ - Install dependencies 🔧 17 | uses: ./.github/workflows/actions/setup_node-cache_dep-install_dep 18 | 19 | - name: Test 🧪 20 | run: npm run test-report 21 | 22 | - name: Upload report 📈 23 | uses: nwtgck/actions-netlify@v3 24 | with: 25 | publish-dir: ${{ env.FOLDER_PATH_TEST_UNIT_REPORT }} 26 | production-deploy: true 27 | env: 28 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} 29 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID_TEST_UNIT_REPORT }} 30 | 31 | - name: Upload coverage to Codecov 📶 32 | uses: codecov/codecov-action@v5 33 | with: 34 | token: ${{ secrets.CODECOV_TOKEN }} 35 | fail_ci_if_error: true 36 | verbose: true 37 | -------------------------------------------------------------------------------- /.github/workflows/tsc.yml: -------------------------------------------------------------------------------- 1 | name: tsc 2 | 3 | on: push 4 | 5 | jobs: 6 | tsc: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout 🛎️ 11 | uses: actions/checkout@v4 12 | 13 | - name: Setup Node.js ⚙️ - Cache dependencies ⚡ - Install dependencies 🔧 14 | uses: ./.github/workflows/actions/setup_node-cache_dep-install_dep 15 | 16 | - name: tsc 🔎 17 | run: npm run tsc 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | compiled 4 | build-storybook-static 5 | 6 | bundle-analysis.html 7 | 8 | .rpt2_cache 9 | 10 | npm-debug.log* 11 | 12 | .DS_Store 13 | .env 14 | *.log 15 | .vscode 16 | .idea 17 | test-unit-report 18 | /test-e2e-results/ 19 | /test-e2e-report/ 20 | /blob-report/ 21 | /playwright/.cache/ 22 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no-install commitlint --edit "$1" -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npm run lint-staged-husky -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | npm run test-report -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*": ["prettier --write --ignore-unknown"], 3 | "*.{js,jsx,ts,tsx}": ["eslint --max-warnings 0"] 4 | } 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | test-unit-report 2 | dist -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "semi": true, 4 | "singleQuote": true, 5 | "trailingComma": "all" 6 | } 7 | -------------------------------------------------------------------------------- /.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | import type { StorybookConfig } from '@storybook/react-webpack5'; 4 | 5 | const storybookConfig: StorybookConfig = { 6 | stories: ['../stories/**/*.stories.tsx'], 7 | framework: { 8 | name: '@storybook/react-webpack5', 9 | options: {}, 10 | }, 11 | 12 | // JSX transform no longer requires importing React explicitly in every file. 13 | swc: () => ({ 14 | jsc: { 15 | transform: { 16 | react: { 17 | runtime: 'automatic', 18 | }, 19 | }, 20 | }, 21 | }), 22 | 23 | webpackFinal: (config) => { 24 | // Resolve absolute imports 25 | config.resolve?.modules?.push(path.resolve(process.cwd(), 'src')); 26 | 27 | return config; 28 | }, 29 | 30 | addons: ['@storybook/addon-webpack5-compiler-swc'], 31 | }; 32 | 33 | // eslint-disable-next-line import-x/no-default-export 34 | export default storybookConfig; 35 | -------------------------------------------------------------------------------- /.storybook/manager.ts: -------------------------------------------------------------------------------- 1 | import { addons } from 'storybook/manager-api'; 2 | 3 | import { theme } from './theme'; 4 | 5 | addons.setConfig({ 6 | theme, 7 | toolbar: { 8 | title: { hidden: false }, 9 | zoom: { hidden: false }, 10 | eject: { hidden: false }, 11 | copy: { hidden: false }, 12 | fullscreen: { hidden: false }, 13 | }, 14 | bottomPanelHeight: 0, 15 | panelPosition: false, 16 | }); 17 | -------------------------------------------------------------------------------- /.storybook/preview.tsx: -------------------------------------------------------------------------------- 1 | import type { Preview } from '@storybook/react-webpack5'; 2 | 3 | const preview: Preview = { 4 | parameters: { 5 | actions: { argTypesRegex: '^on[A-Z].*' }, 6 | controls: { 7 | // Description toggle 8 | // expanded: true, 9 | matchers: { 10 | color: /(background|color)$/i, 11 | date: /Date$/, 12 | }, 13 | }, 14 | }, 15 | }; 16 | 17 | // eslint-disable-next-line import-x/no-default-export 18 | export default preview; 19 | -------------------------------------------------------------------------------- /.storybook/theme.ts: -------------------------------------------------------------------------------- 1 | import { create } from 'storybook/theming'; 2 | 3 | export const theme = create({ 4 | base: 'light', 5 | brandTitle: 'React Parallax Tilt 👀', 6 | brandUrl: 'https://github.com/mkosir/react-parallax-tilt', 7 | }); 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Marko Kosir 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Tilt 2 | 3 | [![npm version][npm-badge]][npm-url] 4 | [![npm downloads][downloads-badge]][npm-url] 5 | [![npm bundle size][size-badge]][size-url] 6 | [![Open issues][issues-badge]][issues-url] 7 | [![TypeScript][typescript-badge]][typescript-url] 8 | [![semantic-release][semantic-badge]][semantic-url] 9 | 10 | [![CI][lint-badge]][lint-url] 11 | [![CI][tsc-badge]][tsc-url] 12 | [![CI][build-badge]][build-url] 13 | [![CI][test-badge]][test-url] 14 | [![CI][test-e2e-badge]][test-e2e-url] 15 | [![Codecov Coverage][coverage-badge]][coverage-url] 16 | 17 | [![CI][deploy-storybook-badge]][deploy-storybook-url] 18 | [![CI][npm-release-badge]][npm-release-url] 19 | 20 | _👀 Easily apply tilt hover effects to React components_ 21 | 22 | [![](misc/demo.gif)](https://mkosir.github.io/react-parallax-tilt/?path=/story/react-parallax-tilt--glare-effect) 23 | 24 | ## [Live Demo 💥](https://mkosir.github.io/react-parallax-tilt) 25 | 26 | ## Install 27 | 28 | ```bash 29 | npm install react-parallax-tilt 30 | ``` 31 | 32 | ## Features 33 | 34 | - Lightweight 3kB, zero dependencies 📦 35 | - Tree-shakable 🌳 ESM and CommonJS support 36 | - Works with React v15 onwards 37 | - Supports **mouse** and **touch** events 38 | - Support for device tilting (**gyroscope**) 39 | - **Glare** effect 🌟 with custom props (color, position, etc.) [🔗demo](https://mkosir.github.io/react-parallax-tilt/?path=/story/react-parallax-tilt--parallax-effect-glare-scale) 40 | - **Event tracking** for component values 📐 (tilt, glare, mousemove, etc.) [🔗demo](https://mkosir.github.io/react-parallax-tilt/?path=/story/react-parallax-tilt--event-params) 41 | - Multiple built-in effects: 42 | - **Scale** on hover [🔗demo](https://mkosir.github.io/react-parallax-tilt/?path=/story/react-parallax-tilt--scale) 43 | - **Disable** x/y axis [🔗demo](https://mkosir.github.io/react-parallax-tilt/?path=/story/react-parallax-tilt--tilt-disable-axis) 44 | - **Flip** component vertically/horizontally [🔗demo](https://mkosir.github.io/react-parallax-tilt/?path=/story/react-parallax-tilt--flip-vh) 45 | - **Window** tilt hover effect [🔗demo](https://mkosir.github.io/react-parallax-tilt/?path=/story/react-parallax-tilt--track-on-window) 46 | - **Manual tilt** control 🕹 (via joystick, slider, etc.) [🔗demo](https://mkosir.github.io/react-parallax-tilt/?path=/story/react-parallax-tilt--tilt-manual-input) 47 | - **Parallax** effect for overlaid images [🔗demo](https://mkosir.github.io/react-parallax-tilt/?path=/story/react-parallax-tilt--parallax-effect-img) 48 | 49 | ## Example 50 | 51 | ```jsx 52 | import Tilt from 'react-parallax-tilt'; 53 | 54 | const App = () => { 55 | return ( 56 | 57 |
58 |

React Parallax Tilt 👀

59 |
60 |
61 | ); 62 | }; 63 | ``` 64 | 65 | ## Props 66 | 67 | All props are optional. 68 | Here's the complete list of available props and their default values: 69 | 70 | > ▶︎ indicates the default value 71 | 72 | **tiltEnable**: _boolean_ ▶︎ `true` 73 | Enables/disables the tilt effect. 74 | 75 | **tiltReverse**: _boolean_ ▶︎ `false` 76 | Reverses the tilt direction. 77 | 78 | **tiltAngleXInitial**: _number_ ▶︎ `0` 79 | Initial tilt angle (in degrees) on the x-axis. 80 | 81 | **tiltAngleYInitial**: _number_ ▶︎ `0` 82 | Initial tilt angle (in degrees) on the y-axis. 83 | 84 | **tiltMaxAngleX**: _number_ ▶︎ `20` 85 | Maximum tilt rotation (in degrees) on the x-axis. Range: `0°-90°`. 86 | 87 | **tiltMaxAngleY**: _number_ ▶︎ `20` 88 | Maximum tilt rotation (in degrees) on the y-axis. Range: `0°-90°`. 89 | 90 | **tiltAxis**: _'x' | 'y'_ ▶︎ `undefined` 91 | Enables tilt on a single axis only. 92 | 93 | **tiltAngleXManual**: _number_ | null ▶︎ `null` 94 | Manual tilt rotation (in degrees) on the x-axis. 95 | 96 | **tiltAngleYManual**: _number_ | null ▶︎ `null` 97 | Manual tilt rotation (in degrees) on the y-axis. 98 | 99 | **glareEnable**: _boolean_ ▶︎ `false` 100 | Enables/disables the glare effect. 101 | 102 | **glareMaxOpacity**: _number_ ▶︎ `0.7` 103 | Maximum glare opacity (`0.5 = 50%, 1 = 100%`). Range: `0-1` 104 | 105 | **glareColor**: _string_ ▶︎ `#ffffff` 106 | Sets the color of the glare effect. 107 | 108 | **glarePosition**: _'top' | 'right' | 'bottom' | 'left' | 'all'_ ▶︎ `bottom` 109 | Sets the position of the glare effect. 110 | 111 | **glareReverse**: _boolean_ ▶︎ `false` 112 | Reverses the glare direction. 113 | 114 | **glareBorderRadius**: _string_ ▶︎ `0` 115 | Sets the border radius of the glare. Accepts any standard CSS border radius value. 116 | 117 | **scale**: _number_ ▶︎ `1` 118 | Scale of the component (`1.5 = 150%, 2 = 200%`). 119 | 120 | **perspective**: _number_ ▶︎ `1000` 121 | Defines how far the tilt component appears from the user. Lower values create more extreme tilt effects. 122 | 123 | **flipVertically**: _boolean_ ▶︎ `false` 124 | Enables/disables vertical flipping of the component. 125 | 126 | **flipHorizontally**: _boolean_ ▶︎ `false` 127 | Enables/disables horizontal flipping of the component. 128 | 129 | **reset**: _boolean_ ▶︎ `true` 130 | Determines if effects should reset on `onLeave` event. 131 | 132 | **transitionEasing**: _string_ ▶︎ `cubic-bezier(.03,.98,.52,.99)` 133 | Easing function for the transition. 134 | 135 | **transitionSpeed**: _number_ ▶︎ `400` 136 | Speed of the transition. 137 | 138 | **trackOnWindow**: _boolean_ ▶︎ `false` 139 | Tracks mouse and touch events across the entire window. 140 | 141 | **gyroscope**: _boolean_ ▶︎ `false` 142 | Enables/disables device orientation detection. 143 | 144 | **onMove**: ({ **tiltAngleX**: _number_, **tiltAngleY**: _number_, **tiltAngleXPercentage**: _number_, **tiltAngleYPercentage**: _number_, **glareAngle**: _number_, **glareOpacity**: _number_, **event**: _Event_ }) => _void_ 145 | Callback triggered when user moves on the component. 146 | 147 | **onEnter**: (**event**: _Event_) => _void_ 148 | Callback triggered when user enters the component. 149 | 150 | **onLeave**: (**event**: _Event_) => _void_ 151 | Callback triggered when user leaves the component. 152 | 153 | ## Gyroscope - Device Orientation 154 | 155 | Please note that device orientation detection is currently [experimental technology](https://developer.mozilla.org/en-US/docs/MDN/Contribute/Guidelines/Conventions_definitions#Experimental). 156 | Check the [browser compatibility](https://caniuse.com/#search=DeviceOrientation) before using it in production. 157 | Important considerations when using device orientation: 158 | 159 | - Always use secure origins (such as `https`) 160 | - It may not work in all browsers when used within a cross-origin `