Buttons button3dinteractive
3D Push Button
A button that physically sinks into the interface when clicked.
Preview
Usage
Copy the full block below to use this component with its imports.
astro
---
import { 3DPushButton } from 'astro-component-kit';
---
<3dPushButton href="#" type="button" color="#6366f1" size="md" disabled={false}>Push Me</3dPushButton> ---
import { 3DPushButton } from 'astro-component-kit';
---
<3dPushButton href="#" type="button" color="#6366f1" size="md" disabled={false}>Push Me</3dPushButton> Manual Installation
If you are not using the npm package, create a new file src/components/lib/3DPushButton.astro and paste the following code:
astro
---
interface Props {
href?: string;
type?: 'button' | 'submit' | 'reset';
color?: string;
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
}
const {
href,
type = 'button',
color = '#6366f1',
size = 'md',
disabled = false
} = Astro.props;
const Tag = href ? 'a' : 'button';
---
<Tag
href={href}
type={href ? undefined : type}
disabled={disabled}
class={`push-btn push-btn--${size}`}
style={`--btn-color: ${color}`}
>
<span class="push-btn__shadow"></span>
<span class="push-btn__edge"></span>
<span class="push-btn__front">
<slot />
</span>
</Tag>
<style>
.push-btn {
--depth: 8px;
position: relative;
display: inline-flex;
padding: 0;
padding-top: var(--depth); /* Space for the elevated front */
border: none;
background: transparent;
cursor: pointer;
outline-offset: 4px;
transition: filter 250ms;
user-select: none;
text-decoration: none;
vertical-align: middle;
}
.push-btn__shadow {
position: absolute;
top: var(--depth); /* Align with base */
left: 0;
width: 100%;
height: calc(100% - var(--depth));
border-radius: var(--r-md, 12px);
background: rgba(0, 0, 0, 0.4);
transform: translateY(2px);
filter: blur(4px);
transition: transform 600ms cubic-bezier(.3, .7, .4, 1);
}
.push-btn__edge {
position: absolute;
top: var(--depth); /* Align with base */
left: 0;
width: 100%;
height: calc(100% - var(--depth));
border-radius: var(--r-md, 12px);
background: linear-gradient(
to left,
color-mix(in srgb, var(--btn-color), black 30%) 0%,
color-mix(in srgb, var(--btn-color), black 15%) 8%,
color-mix(in srgb, var(--btn-color), black 15%) 92%,
color-mix(in srgb, var(--btn-color), black 30%) 100%
);
}
.push-btn__front {
display: block;
position: relative;
padding: 12px 32px;
border-radius: var(--r-md, 12px);
font-size: 1rem;
font-weight: 700;
color: white;
background: var(--btn-color);
transform: translateY(calc(var(--depth) * -1));
transition: transform 600ms cubic-bezier(.3, .7, .4, 1);
font-family: var(--font-sans, inherit);
white-space: nowrap;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.push-btn:hover:not(:disabled) {
filter: brightness(110%);
}
.push-btn:hover:not(:disabled) .push-btn__front {
transform: translateY(calc(var(--depth) * -1.2));
transition: transform 250ms cubic-bezier(.3, .7, .4, 1.5);
}
.push-btn:hover:not(:disabled) .push-btn__shadow {
transform: translateY(4px);
transition: transform 250ms cubic-bezier(.3, .7, .4, 1.5);
}
.push-btn:active:not(:disabled) .push-btn__front {
transform: translateY(-2px);
transition: transform 34ms;
}
.push-btn:active:not(:disabled) .push-btn__shadow {
transform: translateY(1px);
transition: transform 34ms;
}
.push-btn:disabled {
cursor: not-allowed;
filter: grayscale(1) opacity(0.5);
box-shadow: none;
}
/* Sizes */
.push-btn--sm { --depth: 5px; }
.push-btn--sm .push-btn__front { padding: 8px 18px; font-size: 0.85rem; }
.push-btn--md { --depth: 8px; }
.push-btn--md .push-btn__front { padding: 12px 32px; font-size: 1rem; }
.push-btn--lg { --depth: 12px; }
.push-btn--lg .push-btn__front { padding: 16px 42px; font-size: 1.15rem; }
</style> ---
interface Props {
href?: string;
type?: 'button' | 'submit' | 'reset';
color?: string;
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
}
const {
href,
type = 'button',
color = '#6366f1',
size = 'md',
disabled = false
} = Astro.props;
const Tag = href ? 'a' : 'button';
---
<Tag
href={href}
type={href ? undefined : type}
disabled={disabled}
class={`push-btn push-btn--${size}`}
style={`--btn-color: ${color}`}
>
<span class="push-btn__shadow"></span>
<span class="push-btn__edge"></span>
<span class="push-btn__front">
<slot />
</span>
</Tag>
<style>
.push-btn {
--depth: 8px;
position: relative;
display: inline-flex;
padding: 0;
padding-top: var(--depth); /* Space for the elevated front */
border: none;
background: transparent;
cursor: pointer;
outline-offset: 4px;
transition: filter 250ms;
user-select: none;
text-decoration: none;
vertical-align: middle;
}
.push-btn__shadow {
position: absolute;
top: var(--depth); /* Align with base */
left: 0;
width: 100%;
height: calc(100% - var(--depth));
border-radius: var(--r-md, 12px);
background: rgba(0, 0, 0, 0.4);
transform: translateY(2px);
filter: blur(4px);
transition: transform 600ms cubic-bezier(.3, .7, .4, 1);
}
.push-btn__edge {
position: absolute;
top: var(--depth); /* Align with base */
left: 0;
width: 100%;
height: calc(100% - var(--depth));
border-radius: var(--r-md, 12px);
background: linear-gradient(
to left,
color-mix(in srgb, var(--btn-color), black 30%) 0%,
color-mix(in srgb, var(--btn-color), black 15%) 8%,
color-mix(in srgb, var(--btn-color), black 15%) 92%,
color-mix(in srgb, var(--btn-color), black 30%) 100%
);
}
.push-btn__front {
display: block;
position: relative;
padding: 12px 32px;
border-radius: var(--r-md, 12px);
font-size: 1rem;
font-weight: 700;
color: white;
background: var(--btn-color);
transform: translateY(calc(var(--depth) * -1));
transition: transform 600ms cubic-bezier(.3, .7, .4, 1);
font-family: var(--font-sans, inherit);
white-space: nowrap;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.push-btn:hover:not(:disabled) {
filter: brightness(110%);
}
.push-btn:hover:not(:disabled) .push-btn__front {
transform: translateY(calc(var(--depth) * -1.2));
transition: transform 250ms cubic-bezier(.3, .7, .4, 1.5);
}
.push-btn:hover:not(:disabled) .push-btn__shadow {
transform: translateY(4px);
transition: transform 250ms cubic-bezier(.3, .7, .4, 1.5);
}
.push-btn:active:not(:disabled) .push-btn__front {
transform: translateY(-2px);
transition: transform 34ms;
}
.push-btn:active:not(:disabled) .push-btn__shadow {
transform: translateY(1px);
transition: transform 34ms;
}
.push-btn:disabled {
cursor: not-allowed;
filter: grayscale(1) opacity(0.5);
box-shadow: none;
}
/* Sizes */
.push-btn--sm { --depth: 5px; }
.push-btn--sm .push-btn__front { padding: 8px 18px; font-size: 0.85rem; }
.push-btn--md { --depth: 8px; }
.push-btn--md .push-btn__front { padding: 12px 32px; font-size: 1rem; }
.push-btn--lg { --depth: 12px; }
.push-btn--lg .push-btn__front { padding: 16px 42px; font-size: 1.15rem; }
</style>
Quick Info
- Category
- Buttons
- Filename
3DPushButton.astro- Dependencies
- None — pure Astro + CSS
- Tags
- button3dinteractive