Buttons
Curtain Button
A red curtain button, closed by default; on hover both panels sweep open to the sides revealing an outlined red label.
Loading preview
Advertisement
Ad space reserved for a future placement
Source code
"use client";
import type { ButtonHTMLAttributes, ReactNode } from "react";
type CurtainButtonSize = "sm" | "md" | "lg";
interface CurtainButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "color"> {
children: ReactNode;
accentColor?: string;
size?: CurtainButtonSize;
}
const SIZE_CLASSES: Record<CurtainButtonSize, string> = {
sm: "px-4 py-2 text-sm",
md: "px-6 py-3 text-base",
lg: "px-8 py-4 text-lg",
};
export function CurtainButton({
children,
accentColor = "#ef4444",
size = "md",
className,
style,
...props
}: CurtainButtonProps) {
return (
<button
type="button"
className={["curtain-button", SIZE_CLASSES[size], className].filter(Boolean).join(" ")}
style={{ ...style, ["--curtain-accent" as string]: accentColor }}
{...props}
>
<span className="curtain-panel curtain-panel--left" aria-hidden="true" />
<span className="curtain-panel curtain-panel--right" aria-hidden="true" />
<span className="curtain-button-label">{children}</span>
<style jsx>{`
.curtain-button {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
overflow: hidden;
border-radius: 0.5rem;
border: 1.5px solid var(--curtain-accent);
background-color: transparent;
color: var(--curtain-accent);
font-weight: 600;
cursor: pointer;
}
.curtain-panel {
position: absolute;
top: 0;
bottom: 0;
width: 51%;
background-color: var(--curtain-accent);
transition: transform 400ms cubic-bezier(0.16, 1, 0.3, 1);
}
.curtain-panel--left {
left: 0;
}
.curtain-panel--right {
right: 0;
}
.curtain-button:hover .curtain-panel--left,
.curtain-button:focus-visible .curtain-panel--left {
transform: translateX(-100%);
}
.curtain-button:hover .curtain-panel--right,
.curtain-button:focus-visible .curtain-panel--right {
transform: translateX(100%);
}
.curtain-button-label {
position: relative;
color: white;
transition: color 400ms cubic-bezier(0.16, 1, 0.3, 1);
}
.curtain-button:hover .curtain-button-label,
.curtain-button:focus-visible .curtain-button-label {
color: var(--curtain-accent);
}
.curtain-button:focus-visible {
outline: 2px solid var(--curtain-accent);
outline-offset: 2px;
}
.curtain-button:disabled {
cursor: not-allowed;
opacity: 0.5;
}
@media (prefers-reduced-motion: reduce) {
.curtain-panel,
.curtain-button-label {
transition: none;
}
}
`}</style>
</button>
);
}
Usage
Import the component and use it like this.
import { CurtainButton } from "./CurtainButton";
export default function Example() {
return (
<CurtainButton accentColor="#ef4444" size="md">
Get started
</CurtainButton>
);
}
Dependencies
No external dependencies.
Usage notes
Pass an accentColor hex to change the outline/fill color, and size (sm/md/lg) to change padding.