OpenSourceUIOpenSourceUIOpensource UI
GitHub—
  1. Home
  2. Components
  3. Buttons
  4. Sheen Pill
Back to ButtonsComponents / Buttons

Sheen Pill

Free Buttons React component — SheenPillButton. MIT licensed, copy-paste ready for Next.js and Tailwind CSS.

Frosted pill with layered shade veil, light band, and rim wire — hover brightens the sheen and clears the fill. Pass width, height, and highlight to tune the frame.

Preview

Setup

How to use

Free for personal and commercial use. No UI attribution required. Include the MIT copyright notice when copying component source into your project. Read the MIT license.

  1. 1

    Run in your terminal:

    $npm install clsx tailwind-merge lucide-react
  2. 2

    Copy lib/cn.ts below. Skip if you already have cn().

  3. 3

    Copy the code below and create components/buttons/sheen-pill-button.tsx in your project.

  4. 4

    Import and render:

    Example

    import { SheenPillButton } from "@/components/buttons/sheen-pill-button";

    <SheenPillButton width={200} height={60}>Get started</SheenPillButton>

lib/cn.ts

1
2
3
4
5
6
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

components/buttons/sheen-pill-button.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"use client";
 
import {
forwardRef,
type ComponentPropsWithoutRef,
type ReactNode,
} from "react";
 
import { cn } from "@/lib/cn";
 
export type SheenPillButtonProps = Readonly<
{
children: ReactNode;
width?: number;
height?: number;
highlight?: number;
} & ComponentPropsWithoutRef<"button">
>;
 
const SHEEN_PILL_RADIUS = 9999;
 
const SHEEN_SHELL =
"group relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-4 overflow-hidden border border-double border-[rgba(51,51,51,0.08)] bg-[rgba(255,255,255,0.08)] backdrop-blur-[5px] brightness-[1.05]";
 
const SHEEN_SHELL_SHADOW =
"[box-shadow:inset_2px_-2px_1px_-1px_rgba(255,255,255,0.9),inset_-2px_2px_1px_-1px_rgba(255,255,255,0.9),inset_6px_-6px_1px_-6px_rgba(255,255,255,0.55),inset_-6px_6px_1px_-6px_rgba(255,255,255,0.55),inset_0_0_2px_rgba(0,0,0,0.8),0_4px_8px_rgba(0,0,0,0.2)]";
 
const SHEEN_SHELL_HOVER_SHADOW =
"hover:[box-shadow:inset_2px_-2px_1px_-1px_rgba(255,255,255,0.95),inset_-2px_2px_1px_-1px_rgba(255,255,255,0.95),inset_6px_-6px_1px_-6px_rgba(255,255,255,0.65),inset_-6px_6px_1px_-6px_rgba(255,255,255,0.65),inset_0_0_2px_rgba(0,0,0,0.65),0_6px_12px_rgba(0,0,0,0.22)]";
 
export const SheenPillButton = forwardRef<
HTMLButtonElement,
SheenPillButtonProps
>(
(
{
children,
className,
width = 180,
height = 60,
highlight = 15,
type = "button",
disabled,
style,
...props
},
ref,
) => {
const shadeVeilWidth = width - 16;
const shadeVeilHeight = height - 16;
const rimWireWidth = width - 9;
const rimWireHeight = height - 9;
 
return (
<button
ref={ref}
type={type}
disabled={disabled}
data-slot="sheen-pill-button"
className={cn(
SHEEN_SHELL,
"transition-[transform,background-color,box-shadow,filter] duration-250 ease-linear motion-reduce:transition-none",
"hover:scale-[1.02] hover:bg-transparent hover:brightness-110",
"active:scale-100 motion-reduce:hover:scale-100",
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-900",
"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
SHEEN_SHELL_SHADOW,
SHEEN_SHELL_HOVER_SHADOW,
className,
)}
style={{
width,
height,
borderRadius: SHEEN_PILL_RADIUS,
...style,
}}
{...props}
>
<span
aria-hidden="true"
data-layer="sheen-shade-veil"
className="pointer-events-none absolute top-[35%] left-1/2 z-0 -translate-x-1/2 border border-[rgba(0,0,0,0.9)] blur-sm transition-[opacity,transform,filter] duration-250 ease-linear group-hover:opacity-80 group-hover:blur-md motion-reduce:transition-none"
style={{
width: shadeVeilWidth,
height: shadeVeilHeight,
borderRadius: SHEEN_PILL_RADIUS,
}}
/>
 
<span
aria-hidden="true"
data-layer="sheen-light-band"
className="pointer-events-none absolute inset-0 z-10 opacity-80 blur-[7px] transition-[opacity,transform,filter] duration-250 ease-linear group-hover:scale-105 group-hover:opacity-100 group-hover:blur-[9px] motion-reduce:transition-none motion-reduce:group-hover:scale-100"
style={{
borderRadius: SHEEN_PILL_RADIUS,
background: `linear-gradient(45deg, rgba(255,255,255,0.8) 0%, transparent ${highlight}%, transparent calc(100% - ${highlight}%), rgba(255,255,255,0.8) 100%)`,
}}
/>
 
<span
aria-hidden="true"
data-layer="sheen-rim-wire"
className="pointer-events-none absolute top-1/2 left-1/2 z-20 -translate-x-1/2 -translate-y-1/2 border border-[rgba(255,255,255,0.2)] blur-[1px] transition-[border-color,opacity] duration-250 ease-linear group-hover:border-[rgba(255,255,255,0.45)] group-hover:opacity-100 motion-reduce:transition-none"
style={{
width: rimWireWidth,
height: rimWireHeight,
borderRadius: SHEEN_PILL_RADIUS,
}}
/>
 
<span
data-layer="sheen-label-well"
className="relative z-30 flex h-full w-full items-center justify-center gap-4 px-[0.8rem]"
>
<span
data-layer="sheen-label"
className="text-lg leading-none whitespace-nowrap text-[#3e3e3e] filter-[drop-shadow(0_25px_3px_rgba(102,102,102,0.15))] transition-[color,filter,transform] duration-250 ease-linear group-hover:translate-y-[-0.5px] group-hover:text-neutral-800 group-hover:filter-[drop-shadow(0_28px_4px_rgba(102,102,102,0.2))] motion-reduce:transition-none motion-reduce:group-hover:translate-y-0"
>
{children}
</span>
</span>
</button>
);
},
);
 
SheenPillButton.displayName = "SheenPillButton";
PreviousNext

On this

page

Jump to a section on this page.

  • lib/cn.ts
  • components/buttons/sheen-pill-button.tsx
Platinum slotAvailable

Feature your product here.

Sticky card next to every component — highest-intent placement.

Claim this card