Buttons buttonpremium
Tilt Glow Button
A premium button generated dynamically from codebase.
Preview
Usage
Copy the full block below to use this component with its imports.
astro
---
import { TiltGlowButton } from 'astro-component-kit';
---
<TiltGlowButton href="#" type="button" variant="primary" size="md">Click Me</TiltGlowButton> ---
import { TiltGlowButton } from 'astro-component-kit';
---
<TiltGlowButton href="#" type="button" variant="primary" size="md">Click Me</TiltGlowButton> Manual Installation
If you are not using the npm package, create a new file src/components/lib/TiltGlowButton.astro and paste the following code:
astro
---
/**
* TiltGlowButton — An interactive 3D button that tilts towards the cursor with dynamic lighting.
*
* @param {string} href - Optional. If provided, renders an <a> tag instead of <button>.
* @param {'button'|'submit'|'reset'} type - Optional. The HTML button type. Default is 'button'.
* @param {string} primaryColor - Optional. The primary light/gradient effect color.
* @param {string} secondaryColor - Optional. The secondary lighting/gradient reflection color.
* @param {'sm'|'md'|'lg'} size - Optional. The size variant of the button. Default is 'md'.
* @param {boolean} disabled - Optional. Whether the button is disabled. Default is false.
*/
interface Props {
href?: string;
type?: 'button' | 'submit' | 'reset';
primaryColor?: string;
secondaryColor?: string;
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
}
const {
href,
type = 'button',
primaryColor = '#6366f1',
secondaryColor = '#c084fc',
size = 'md',
disabled = false
} = Astro.props;
const Tag = href ? 'a' : 'button';
---
<div class={`tilt-wrapper tilt-wrapper--${size}`}>
<Tag
href={href}
type={href ? undefined : type}
disabled={disabled}
class="tilt-card"
style={`--primary-color: ${primaryColor}; --secondary-color: ${secondaryColor};`}
>
<div class="tilt-card__glow"></div>
<div class="tilt-card__content">
<slot />
</div>
</Tag>
</div>
<style>
.tilt-wrapper {
perspective: 1000px;
display: inline-block;
}
.tilt-card {
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: #0f172a;
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: var(--r-md, 12px);
cursor: pointer;
text-decoration: none;
overflow: hidden;
transition: transform 0.15s ease-out, box-shadow 0.3s ease;
transform-style: preserve-3d;
user-select: none;
font-family: var(--font-sans, inherit);
font-weight: 600;
}
.tilt-card__glow {
position: absolute;
inset: 0;
background: radial-gradient(
circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
color-mix(in srgb, var(--primary-color), white 20%) 0%,
transparent 70%
);
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
z-index: 1;
}
.tilt-card__content {
position: relative;
z-index: 2;
transform: translateZ(20px);
white-space: nowrap;
}
.tilt-card:hover {
box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.5);
border-color: rgba(255, 255, 255, 0.2);
}
.tilt-card:hover .tilt-card__glow {
opacity: 0.15;
}
.tilt-card:active {
transform: scale(0.98) translateZ(0);
}
.tilt-card:disabled {
opacity: 0.5;
cursor: not-allowed;
filter: grayscale(1);
}
/* Sizes */
.tilt-wrapper--sm .tilt-card { padding: 0.5rem 1.4rem; font-size: 0.8rem; }
.tilt-wrapper--md .tilt-card { padding: 0.8rem 2rem; font-size: 0.95rem; }
.tilt-wrapper--lg .tilt-card { padding: 1.1rem 3rem; font-size: 1.1rem; }
</style>
<script>
function initTilt() {
const cards = document.querySelectorAll('.tilt-card:not([data-tilt-init])');
cards.forEach(card => {
card.setAttribute('data-tilt-init', 'true');
const htmlCard = card as HTMLElement;
card.addEventListener('mousemove', (e: any) => {
const rect = htmlCard.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// Calculate percentages for the glow highlight
const xPerc = (x / rect.width) * 100;
const yPerc = (y / rect.height) * 100;
htmlCard.style.setProperty('--mouse-x', `${xPerc}%`);
htmlCard.style.setProperty('--mouse-y', `${yPerc}%`);
// Calculate rotation
const rotateY = (x / rect.width - 0.5) * 25;
const rotateX = (y / rect.height - 0.5) * -25;
htmlCard.style.transform = `rotateY(${rotateY}deg) rotateX(${rotateX}deg)`;
});
card.addEventListener('mouseleave', () => {
htmlCard.style.transform = 'rotateY(0deg) rotateX(0deg)';
htmlCard.style.setProperty('--mouse-x', '50%');
htmlCard.style.setProperty('--mouse-y', '50%');
});
});
}
initTilt();
document.addEventListener('astro:after-swap', initTilt);
</script>
---
/**
* TiltGlowButton — An interactive 3D button that tilts towards the cursor with dynamic lighting.
*
* @param {string} href - Optional. If provided, renders an <a> tag instead of <button>.
* @param {'button'|'submit'|'reset'} type - Optional. The HTML button type. Default is 'button'.
* @param {string} primaryColor - Optional. The primary light/gradient effect color.
* @param {string} secondaryColor - Optional. The secondary lighting/gradient reflection color.
* @param {'sm'|'md'|'lg'} size - Optional. The size variant of the button. Default is 'md'.
* @param {boolean} disabled - Optional. Whether the button is disabled. Default is false.
*/
interface Props {
href?: string;
type?: 'button' | 'submit' | 'reset';
primaryColor?: string;
secondaryColor?: string;
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
}
const {
href,
type = 'button',
primaryColor = '#6366f1',
secondaryColor = '#c084fc',
size = 'md',
disabled = false
} = Astro.props;
const Tag = href ? 'a' : 'button';
---
<div class={`tilt-wrapper tilt-wrapper--${size}`}>
<Tag
href={href}
type={href ? undefined : type}
disabled={disabled}
class="tilt-card"
style={`--primary-color: ${primaryColor}; --secondary-color: ${secondaryColor};`}
>
<div class="tilt-card__glow"></div>
<div class="tilt-card__content">
<slot />
</div>
</Tag>
</div>
<style>
.tilt-wrapper {
perspective: 1000px;
display: inline-block;
}
.tilt-card {
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: #0f172a;
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: var(--r-md, 12px);
cursor: pointer;
text-decoration: none;
overflow: hidden;
transition: transform 0.15s ease-out, box-shadow 0.3s ease;
transform-style: preserve-3d;
user-select: none;
font-family: var(--font-sans, inherit);
font-weight: 600;
}
.tilt-card__glow {
position: absolute;
inset: 0;
background: radial-gradient(
circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
color-mix(in srgb, var(--primary-color), white 20%) 0%,
transparent 70%
);
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
z-index: 1;
}
.tilt-card__content {
position: relative;
z-index: 2;
transform: translateZ(20px);
white-space: nowrap;
}
.tilt-card:hover {
box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.5);
border-color: rgba(255, 255, 255, 0.2);
}
.tilt-card:hover .tilt-card__glow {
opacity: 0.15;
}
.tilt-card:active {
transform: scale(0.98) translateZ(0);
}
.tilt-card:disabled {
opacity: 0.5;
cursor: not-allowed;
filter: grayscale(1);
}
/* Sizes */
.tilt-wrapper--sm .tilt-card { padding: 0.5rem 1.4rem; font-size: 0.8rem; }
.tilt-wrapper--md .tilt-card { padding: 0.8rem 2rem; font-size: 0.95rem; }
.tilt-wrapper--lg .tilt-card { padding: 1.1rem 3rem; font-size: 1.1rem; }
</style>
<script>
function initTilt() {
const cards = document.querySelectorAll('.tilt-card:not([data-tilt-init])');
cards.forEach(card => {
card.setAttribute('data-tilt-init', 'true');
const htmlCard = card as HTMLElement;
card.addEventListener('mousemove', (e: any) => {
const rect = htmlCard.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// Calculate percentages for the glow highlight
const xPerc = (x / rect.width) * 100;
const yPerc = (y / rect.height) * 100;
htmlCard.style.setProperty('--mouse-x', `${xPerc}%`);
htmlCard.style.setProperty('--mouse-y', `${yPerc}%`);
// Calculate rotation
const rotateY = (x / rect.width - 0.5) * 25;
const rotateX = (y / rect.height - 0.5) * -25;
htmlCard.style.transform = `rotateY(${rotateY}deg) rotateX(${rotateX}deg)`;
});
card.addEventListener('mouseleave', () => {
htmlCard.style.transform = 'rotateY(0deg) rotateX(0deg)';
htmlCard.style.setProperty('--mouse-x', '50%');
htmlCard.style.setProperty('--mouse-y', '50%');
});
});
}
initTilt();
document.addEventListener('astro:after-swap', initTilt);
</script>
Quick Info
- Category
- Buttons
- Filename
TiltGlowButton.astro- Dependencies
- None — pure Astro + CSS
- Tags
- buttonpremium