React Next Tilt
A Performant Customizable Tilt Component for React
Main Demo • Control Element Demo • Storybook
Table of Contents
Features
- Easy to use
- Zero dependencies
- Highly customizable
- Touch and Gyroscope support
- Two customizable glare effects (spot/line)
- Parallax ready
-
"Scale on Hover/Touch"
support -
"Shadow on Hover/Touch"
support -
"Disable Scroll on Touch"
support -
"Full-Page Listening"
support -
"Control Element"
support - No jittery movement around the edges
- Built with performance in mind (
requestAnimationFrame()
,will-change
, and other optimizations) - Built from the ground up using React Hooks/TypeScript (is not a port of another library)
- Minimum amount of component re-renders
- Typed props with JSDoc descriptions
- Tested extensively using Cypress/Storybook
Installation
$ npm install react-next-tilt
Once the package is installed, you can import
the component:
import { Tilt } from 'react-next-tilt';
Usage
Basic Usage
Place the element/component you want the tilt effect to be applied to inside of <Tilt></Tilt>
.
<Tilt>
<img src="path/to/image.jpg" />
</Tilt>
You can place any element/component inside of
<Tilt></Tilt>
(doesn't have to be an image)
Parallax Effect
This component is "parallax ready", meaning you don't need to change any settings for it to work.
You just need to set up your parallax effect in JSX/CSS and place it inside of <Tilt></Tilt>
You can read this article to learn more about how to set up the 3D parallax effect.
⚠️ SettinglineGlareMixBlendMode
and/orspotGlareMixBlendMode
properties to anything other than"normal"
will break the parallax effect.
Props
All props are optional.
In addition to these props, you can use any valid
HTMLDivElement
props likeclassName=''
,data-...='...'
,onMouseMove={...}
etc. they will be applied to the container element.
While you can tilt the component to a given angle by adjusting the initial angles, it will cause the component to re-render. It is advised to use the
tilt()
function exposed by the component's ref instead.
Name | Description | Default |
---|---|---|
width |
Width of the component
note: You can also set the width using "className", "style", etc. instead of using this property
example: 100, '200px', '10rem', '20%'
string | number |
- |
height |
Height of the component
note: You can also set the height using "className", "style", etc. instead of using this property
example: 100, '200px', '10rem', '20%'
string | number |
- |
borderRadius |
Border radius of the component (applied to glare elements as well)
example: '4px', '1em', '2rem'
string |
- |
perspective |
Determines how far the elements are from the user
example: '1000px', '60em', '50rem'
string |
"1000px" |
scale |
Amount of scale applied to the component on hover/touch
number |
1 |
shadowEnable |
Enables/Disables the shadow applied to the container or tilt element on hover/touch
boolean |
false |
shadow |
The shadow applied to the container or tilt element on hover/touch
string |
"0 0 1rem rgba(0,0,0,0.5)" |
shadowType |
Type of the shadow applied on hover/touch
If set to
'box' , shadow is applied as box-shadow to the tilt elementIf set to
'drop' , shadow is applied as filter: drop-shadow() to the container elementnote: Set to
'drop' if you have a setup where elements go outside the tilt element and want to apply the shadow to them as well,Or if you have multiple elements inside the tilt element and want the shadow to apply to them individually and not the whole tilt element
"box" | "drop" |
"box" |
lineGlareEnable |
Enables/Disables the line glare effect
boolean |
true |
lineGlareBlurEnable |
Enables/Disables the blur applied to the line glare effect
boolean |
true |
lineGlareBlurAmount |
Amount of blur applied to the line glare effect
example: '4px', '1em', '2rem'
string |
"4px" |
lineGlareWidthPercent |
Width of the line glare in relation to the component
number |
10 |
lineGlareMaxOpacity |
Maximum opacity of the line glare effect
number |
0.1 |
lineGlareMixBlendMode |
mix-blend-mode applied to the line glare effectnote: Using a "mix-blend-mode" other than "normal" will break the parallax effect
string (Property.MixBlendMode) |
"normal" |
lineGlareColor |
Color of the line glare effect
example: 'lightblue', '#445566AA', 'rgba(50,150,250,0.5)', 'hsla(100,50%,50%,0.2)'
string (Property.Color) |
"white" |
lineGlareReverse |
Reverses the movement of the line glare effect
boolean |
false |
lineGlareDirection |
Changes the direction/angle of the line glare effect
"to-bottom-right" | "to-bottom-left" |
"to-bottom-right" |
lineGlareHoverPosition |
Determines the areas of the component that show the line glare effect when hovered/touched
"top-left" | "top-right" | "bottom-left" | "bottom-right" |
"top-left" |
lineGlareFixedPosition |
Sets the position of the line glare element to a fixed position inside the component.
note:
The position determines the center of the line glare element.
The
left property can be specified in pixels ('px') or percentage ('%').When set, the line glare element will not respond to hover/touch and will always be at the specified position.
"left" | "right" | "center" | { left: `${number}px` | `${number}%`; } |
- |
spotGlareEnable |
Enables/Disables the spot glare effect
boolean |
true |
spotGlareSizePercent |
Size of the spot glare effect in relation to the component between
0 to Infinity note: If
spotGlarePosition is set to anything other than 'all' , only half of the spot glare effect is visible at any time.That's why the default value is 200 to cover the whole element.
number |
200 |
spotGlareMaxOpacity |
Maximum opacity of the spot glare effect
number |
0.5 |
spotGlareMixBlendMode |
mix-blend-mode applied to the spot glare effectnote: Using a "mix-blend-mode" other than "normal" will break the parallax effect
string (Property.MixBlendMode) |
"normal" |
spotGlarePosition |
Determines the position of the spot glare effect inside the component
"top" | "right" | "bottom" | "left" | "all" |
"top" |
spotGlareColor |
Color of the line glare effect
example: 'lightblue', '#445566AA', 'rgba(50,150,250,0.5)', 'hsla(100,50%,50%,0.2)'
string (Property.Color) |
"white" |
spotGlareReverse |
Reverses the movement of the spot glare effect
boolean |
false |
spotGlareFixedPosition |
Sets the position of the spot glare element to a fixed position inside the component.
note:
The position determines the center of the spot glare element.
The
left and top properties can be specified in pixels ('px') or percentage ('%').When set, the spot glare element will not respond to hover/touch and will always be at the specified position.
"top-left" | "top-right" | "bottom-left" | "bottom-right" | "center" | { left: `${number}px` | `${number}%`; top: `${number}px` | `${number}%`; } |
- |
tiltMaxAngleX |
Maximum tilt angle around the X axis between 0 to 90
note: Setting to 0 will disable rotation around the X axis
number |
20 |
tiltMaxAngleY |
Maximum tilt angle around the Y axis between 0 to 90
note: Setting to 0 will disable rotation around the Y axis
number |
20 |
tiltReverse |
Reverses the tilt direction/movement
boolean |
false |
tiltReset |
Enables/Disables resetting the tilt effect on mouseLeave/touchEnd
boolean |
true |
initialAngleX |
Initial tilt/rotation angle around the X axis
note: Is limited to [-tiltMaxAngleX - tiltMaxAngleX] range
number |
- |
initialAngleY |
Initial tilt/rotation angle around the Y axis
note: Is limited to [-tiltMaxAngleY - tiltMaxAngleY] range
number |
- |
disableScrollOnTouch |
Disables scrolling (
overflow: hidden ) during touch inetraction to prevent unwanted movementnote: Disables scrolling on "body" if set to "boolean". You can also pass an "HTMLElement" which scrolling will be disabled for, instead of "body"
boolean | HTMLElement |
true |
style |
Style passed to the component's container element
CSSProperties |
- |
tiltStyle |
Style passed to the component's tilt element
CSSProperties |
- |
tiltClass |
className passed to the component's tilt element
string |
- |
tiltProps |
Properties passed to the tilt element
HTMLAttributes<HTMLDivElement> & { [data: `data-${string}`]: string; } |
- |
gyroMaxAngleX |
Maximum tilt angle around the X axis for gyroscope between 0 to 90
note: Setting to 0 will disable rotation around the X axis for gyroscope
number |
0 |
gyroMaxAngleY |
Maximum tilt angle around the Y axis for gyroscope between 0 to 90
note: Setting to 0 will disable rotation around the Y axis for gyroscope
number |
0 |
gyroReverse |
Reverses the tilt direction for gyroscope
boolean |
false |
disabled |
Disables the tilt effect and applies the disabledFilter to the container
boolean |
false |
disabledFilter |
CSS filter applied to the container when
disabled = true string |
"grayscale(1) brightness(125%)" |
CSSTransition |
CSS transition applied to the tilt, line glare, and spot glare elements
string |
"all 0.4s cubic-bezier(0.03, 0.98, 0.52, 0.99)" |
TiltWrapper |
Component wrapping the tilt element
note: Is useful when integrating this component into another component
FC<{ children?: ReactNode; }> |
({ children }: PropsWithChildren) => <>{children}</> |
fullPageListening |
Enables/Disables full-page listening. This component's event handlers will be added to the "document"
ote: If set to "true", "controlElement", "controlElementOnly", and "disableScrollOnTouch" properties will have no effect
boolean |
false |
controlElement |
Element(s) that control(s) this component. This component's event handlers will be added to them
note: You can pass an HTMLElement, a ref, or an array of them
This property will have no effect if "fullPageListening" is set to "true"
example: element, ref, [element, ref], [ref1, ref2]
HTMLElement | RefObject<unknown> | (HTMLElement | RefObject<unknown>)[] |
- |
controlElementOnly |
If set to "true", events will be disabled for the component and it will be controlled by the controlElement(s) only
This property will have no effect if "fullPageListening" is set to "true"
boolean |
false |
preserve3dEnable |
If set to true, adds
transform-style: preserve-3d; to the container and tilt elementsnote: Enable if you want to set up a parallax effect and translate elements along the
Z axisDisable if you are having problems with blur
warning: Can cause blur on scale (prevents re-rastering at higher scales by Chrome's compositor and the element is always rasterized at scale 1)
boolean |
true |
testIdEnable |
Adds the
data-testid=... property to all elements for testing purposesnote: Can also be used to select/grab and modify each element if you want to do heavy customization
boolean |
false |
Events/Callbacks
Name | Description | Parameters |
---|---|---|
onTilt |
Callback function that is called with the current tilt angle at every tilt event
(angle: Angle, gyro:boolean) => void |
angle : Tilt angle ({angleX: number, angleY: number})gyro : Whether the event is triggered by gyroscope or not |
onReset |
Callback function that is called when the tilt angle is reset
() => void |
Ref
The component's ref object contains these properties:
Name | Description | Parameters |
---|---|---|
element |
The component's main container element
HTMLDivElement | null | - |
tilt |
Tilts the component to the given angle
(angle: Angle, changeScaleAndShadow?: boolean, gyro?: boolean) => void |
angle : Tilt angle ({angleX: number, angleY: number})changeScaleAndShadow=false : Whether to apply the scale and shadow properties or notgyro=false : Whether the event is triggered by gyro or not |
reset |
Resets the component (rotation/scale and glare effects)
() => void | - |
angle |
Returns the current tilt angle ({angleX: number, angleY: number})
() => Angle | - |
updateWillChange |
Adds/Removes the "will-change" CSS property to the tilt and glare elements
note: Can improve performance when doing a series of animations using the "TiltRef.tilt()" function (add?: boolean) => void | add=true : Whether to add the property (true) or remove it (false) |
Ref functions don't re-render the component.
Ref Usage (ref function)
import { Tilt } from 'react-next-tilt';
const MyComponent = () => {
return (
<Tilt
ref={(ref) => {
if (ref) {
//do something with the ref
}
}}
>
...
</Tilt>
);
};
Ref Usage (useEffect)
import { useRef, useEffect } from 'react';
import { Tilt, TiltRef } from 'react-next-tilt';
const MyComponent = () => {
const ref = useRef<TiltRef>(null);
useEffect(() => {
if (ref.current) {
//do something with the ref
}
}, []);
return <Tilt ref={ref}>...</Tilt>;
};
Tilt on Mount
import { useRef, useEffect } from 'react';
import { Tilt, TiltRef } from 'react-next-tilt';
const MyComponent = () => {
const ref = useRef<TiltRef | null>(null);
useEffect(()=>{
if (ref.current) {
//do something else with the ref
}
},[]);
return (
<Tilt
ref={(r) => {
if (r) {
console.log(`angle = ${JSON.stringify(r.angle())}`);
r.tilt({ angleX: 10, angleY: 10 });
console.log(`angle = ${JSON.stringify(r.angle())}`);
ref.current = r;
}
}}
...
>
...
</Tilt>
);
};
Author
Rashid Shamloo (github.com/rashidshamloo)