CSS Class / Style
HoverTilt wraps your content with two elements:
- A
containerelement that handles perspective and listens for pointer events. - An inner
tiltelement that applies transforms and contains the glare effect.
Styling the internals
Section titled “Styling the internals”Here’s a look at the internal structure of the rendered component;
<div class="hover-tilt-container"> └── <div class="hover-tilt"> └── slotted contentIn Svelte, you can style the component’s internal elements via class on the <HoverTilt>, and then build a css declaration, or apply TailwindCSS classes directly to the component.
<HoverTilt class="my-component"> <div class="content-area"> Your content here </div></HoverTilt>.my-component { border-radius: 24px; .hover-tilt { opacity: 0.5; }}.content-area { border-radius: 24px;}<HoverTilt class="rounded-3xl [&_.hover-tilt]:opacity-50"> <div class="rounded-3xl"> Your content here </div></HoverTilt><hover-tilt> ├── #shadow-root │ └── <div part="container"> │ └── <div part="tilt"> │ └── <slot /> └── slotted content (Light DOM)So for internal styling on the web-component,
use ::part(container) and ::part(tilt) CSS selectors to style the shadow DOM elements.
::part(container)
Section titled “::part(container)”wraps the tilt effect.
Generally you don’t want to modify the style of this,
except for things like perspective or perspective-origin.
::part(tilt)
Section titled “::part(tilt)”is the animated layer that holds the glare pseudo-element.
::part(tilt) inherits the border-radius of the container, so you can
either apply a radius to the ::part(container) or the ::part(tilt)
(see below for more details).
<hover-tilt class="my-component"> <div class="content-area"> Your content here </div></hover-tilt>.my-component::part(container) { border-radius: 24px;}.my-component::part(tilt) { opacity: 0.5;}.content-area { border-radius: 24px;}<hover-tilt class="[&::part(container)]:rounded-3xl [&::part(tilt)]:opacity-50"> <div class="rounded-3xl"> Your content here </div></hover-tilt>CSS custom properties
Section titled “CSS custom properties”<HoverTilt /> mirrors its internal properties into CSS variables so you can style content,
gradients, or additional layers without writing extra JavaScript. These values are emitted on the
container element (or ::part(container) in the Web Component).
| Variable | Description / Units |
|---|---|
--hover-tilt-x | Pointer X position (0–1). Handy for gradients or lighting. |
--hover-tilt-y | Pointer Y position (0–1). |
--hover-tilt-opacity | Activation amount mirrored from the internal spring. |
--hover-tilt-scale | Current scale factor (used by the built-in hover grow). |
--hover-tilt-rotation-x | Current tilt rotation around the X axis in degrees. |
--hover-tilt-rotation-y | Current tilt rotation around the Y axis in degrees. |
--hover-tilt-glare-intensity | Matches the glareIntensity prop. |
--hover-tilt-glare-hue | Matches the glareHue prop. |
--hover-tilt-shadow-blur | Matches the shadowBlur prop. |
--hover-tilt-angle | Clockwise pointer angle in degrees (0–360). Great for conic gradients. |
--hover-tilt-from-center | Distance from the center in pixels; useful for falloff effects. |
--hover-tilt-at-edge | Closeness to any edge (0–1). Useful for edge-effects. |
Other considerations
Section titled “Other considerations”There’s a couple of other considerations to keep in mind when styling the component, due to the way it is structured and how web-components work.
border-radius on glare
Section titled “border-radius on glare”If you are applying a border-radius to the content, you may notice that the
glare overflows the radius. This is because the glare is applied to the ::before pseudo-element of the .hover-tilt element.
So you typically want the container to match border radii (or any clipping) on that inner layer to avoid the glare spilling past rounded corners. (see example below)
The Svelte Component exposes a class prop on the container. And the
tilt and ::before elements both inherit the border-radius of the container.
So as long as we apply the same border-radius to the container as the content,
the glare will not overflow the radius.
Overflowing Radius
This card has a radius on the content, but no radius on the container. The glare will overflow the radius.
Fixed Radius
This card has a radius on the container and the content. The glare will not overflow the radius.
<HoverTilt class="rounded-3xl"> <div class="rounded-3xl"> <!-- this radius matches the container --> Your content here </div></HoverTilt>The custom element renders inside Shadow DOM, so classes on <hover-tilt>
only affect the host and not the internal container/tilt nodes.
Use the CSS ::part() selector to
reach those internal elements.
Overflowing Radius
This card has a radius on the content, but no radius on the container. The glare will overflow the radius.
Fixed Radius
This card has a radius on the container and the content. The glare will not overflow the radius.
<hover-tilt class="tilt-card"> <div class="content-card"> Your content here </div></hover-tilt>/* apply radius to both the container and the content */.tilt-card::part(container), .content-card { border-radius: 24px;}With TailwindCSS it’s a bit easier;
<hover-tilt class="[&::part(container)]:rounded-3xl"> <div class="content-card rounded-3xl"> Your content here </div></hover-tilt>overflow on container
Section titled “overflow on container”Because the tilt element is inside of the container, if you apply an overflow: hidden
to the container, the tilt effect will be cut off and look broken.
If you need to clip content to the card area, then apply an overflow: hidden
to the tilt element, or more preferably to the slotted content.
perspective of the tilt effect
Section titled “perspective of the tilt effect”The <HoverTilt> component has a default perspective of 600px.
If you need to change the perspective, you can apply it to the container with CSS;
<HoverTilt class="my-component"> Your content here</HoverTilt>.my-component { perspective: 300px;}<HoverTilt class="pespective-near"> <!-- perspective-near is 300px --> Your content here</HoverTilt><hover-tilt class="my-component"> Your content here</hover-tilt>.my-component::part(container) { perspective: 300px;}<hover-tilt class="[&::part(container)]:perspective-near"> <!-- perspective-near is 300px --> Your content here</hover-tilt>content over the glare
Section titled “content over the glare”You may notice that the glare effect sits on top of the slotted content, this means that if you have text inside the slotted content, it will be covered by the glare.
While this is phsyically correct, it may not be visually desirable. So it’s possible to move the slotted content up in the z-order to sit atop the glare.
Behind Glare
Over Glare
All we need to do is apply a z-index to the slotted content to move it up in the z-order.
<HoverTilt class="my-component"> <div class="content-area"> Your content here </div></HoverTilt>.my-component .content-area { z-index: 10;}<HoverTilt> <div class="z-10"> Your content here </div></HoverTilt><hover-tilt class="my-component"> <div class="content-area"> Your content here </div></hover-tilt>.my-component .content-area { z-index: 10;}<hover-tilt> <div class="z-10"> Your content here </div></hover-tilt>z-index adjacent components
Section titled “z-index adjacent components”If you are using the scaleFactor prop, you may find that when the component zooms in, it overlaps with other components nearby. This will be especially noticeable in a gallery of scaling cards;
Basic Example
Hover over this card to see the default tilt effect
Basic Example
Hover over this card to see the default tilt effect
But it is easily resolved by applying a z-index to the <HoverTilt> component when it is being hovered;
<HoverTilt scaleFactor={1.3} class="my-component"> Your content here</HoverTilt>.my-component:hover { z-index: 10;}<HoverTilt scaleFactor={1.3} class="hover:z-10"> Your content here</HoverTilt><hover-tilt scale-factor={1.3} class="my-component"> Your content here</hover-tilt>.my-component:hover { z-index: 10;}<hover-tilt scale-factor={1.3} class="hover:z-10"> Your content here</hover-tilt>Basic Example
Hover over this card to see the default tilt effect
Basic Example
Hover over this card to see the default tilt effect
This is not a part of the component’s internals because every use case is different and it would have been frustrating for users to battle with a :hover selector, and z-index value they didn’t want.
Making it something you have to handle manually means you can use different, more complex logic instead of just :hover {} selectors (if you desire).