33 / 51
All 51 in 51 Tailwind CSS Buttons
- 01Tailwind Submit Button (Form Primary)
- 02Tailwind Primary and Secondary Button Pair
- 03Tailwind Ghost / Outline Button
- 04Tailwind Icon-Only Button with Accessible Tooltip
- 05Tailwind Gradient CTA Button
- 06Tailwind Loading Spinner Button (State Transition)
- 07Tailwind Disabled Button State (Full State Reference)
- 08Tailwind Button Group Component (Segmented Radio-Like)
- 09Tailwind Add to Cart Button
- 10Tailwind Download Progress Button
- 11Tailwind Like Heart Button
- 12Tailwind Confirm Delete Button
- 13Tailwind Play Pause Button
- 14Tailwind Subscribe Confetti Button
- 15Tailwind Magnetic Mercury Ripple Button
- 16Tailwind Brutalist Glitch Button
- 17Tailwind Neon Plasma Burst Button
- 18Tailwind Clay Press Button
- 19Tailwind Editorial Ink Spread Button
- 20Tailwind Particle Shard Burst Button
- 21Tailwind Brushed Brass Plate Button
- 22Tailwind Washi Paper Crane Button
- 23Tailwind Frosted Ice Cube Button
- 24Tailwind Vintage Typewriter Key Button
- 25Tailwind Lacquered Walnut Wood Button
- 26Tailwind Pharma Gel Capsule Button
- 27Tailwind Aged Copper Coin Button
- 28Tailwind Origami Fortune Cookie Button
- 29Tailwind Holographic Foil Sticker Button
- 30Tailwind Brutalist Concrete Slab Button
- 31Tailwind Mercury Bead Morph Button
- 32Tailwind Soft Pill Modern SaaS Button
- 33Tailwind Masking Tape Label Button
- 34Tailwind Obsidian Glass Shard Button
- 35Tailwind Wine Velvet Ribbon Button
- 36Tailwind LED Segment Display Button
- 37Tailwind Cassette Mixtape Label Button
- 38Tailwind Chalkboard Menu Button
- 39Tailwind Vinyl Record Sleeve Ripple Button
- 40Tailwind Polaroid Snapshot Button
- 41Tailwind Airline Boarding Pass Button
- 42Tailwind Aged Brass Subway Token Button
- 43Tailwind Vintage Rx Pharmacy Label Button
- 44Tailwind Bakelite Radio Dial Toggle Button
- 45Tailwind Regal Postage Stamp Button
- 46Tailwind Victorian Cigar Band Foil Button
- 47Tailwind Vintage Calculator Key Button
- 48Tailwind Toolbox Latch Spotlight Button
- 49Tailwind Receipt Paper Total Count-Up Button
- 50Tailwind IBM Punch Card Magnetic Follow Button
- 51Tailwind Brass Periscope Lens Button
Tailwind Masking Tape Label Button
A strip of drafting tape stuck slightly crooked: translucent so the surface shows through, fibrous weave running lengthwise, ragged torn ends cut by a repeating mask, and a hand-written label. Hover presses the tape flatter; pressing sticks it down.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<div class="tb-33 w-full min-h-svh grid place-items-center font-tb33-hand p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="tb-33__tape group cursor-pointer border-0 px-10 py-3.5 rounded-none text-2xl font-semibold tracking-[0.01em] text-tb33-ink -rotate-[1.7deg] drop-shadow-[0_4px_5px_#3c301e47] transition-[rotate,translate,filter] duration-[400ms] ease-tb33-out [-webkit-tap-highlight-color:transparent] hover:-rotate-[0.4deg] hover:-translate-y-0.5 hover:drop-shadow-[0_8px_9px_#3c301e4d] focus-visible:-rotate-[0.4deg] focus-visible:-translate-y-0.5 focus-visible:outline-2 focus-visible:outline-dashed focus-visible:outline-tb33-ink focus-visible:outline-offset-4 active:-rotate-[1.2deg] active:translate-y-px active:drop-shadow-[0_2px_2px_#3c301e4d] disabled:cursor-not-allowed disabled:opacity-60 disabled:drop-shadow-none motion-reduce:transition-none motion-reduce:hover:rotate-0">
<span class="inline-block transition-[rotate] duration-[400ms] ease-tb33-out group-hover:rotate-[0.6deg] group-focus-visible:rotate-[0.6deg] motion-reduce:transition-none">pin this for later</span>
</button>
</div><div class="tb-33 w-full min-h-svh grid place-items-center font-tb33-hand p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="tb-33__tape group cursor-pointer border-0 px-10 py-3.5 rounded-none text-2xl font-semibold tracking-[0.01em] text-tb33-ink -rotate-[1.7deg] drop-shadow-[0_4px_5px_#3c301e47] transition-[rotate,translate,filter] duration-[400ms] ease-tb33-out [-webkit-tap-highlight-color:transparent] hover:-rotate-[0.4deg] hover:-translate-y-0.5 hover:drop-shadow-[0_8px_9px_#3c301e4d] focus-visible:-rotate-[0.4deg] focus-visible:-translate-y-0.5 focus-visible:outline-2 focus-visible:outline-dashed focus-visible:outline-tb33-ink focus-visible:outline-offset-4 active:-rotate-[1.2deg] active:translate-y-px active:drop-shadow-[0_2px_2px_#3c301e4d] disabled:cursor-not-allowed disabled:opacity-60 disabled:drop-shadow-none motion-reduce:transition-none motion-reduce:hover:rotate-0">
<span class="inline-block transition-[rotate] duration-[400ms] ease-tb33-out group-hover:rotate-[0.6deg] group-focus-visible:rotate-[0.6deg] motion-reduce:transition-none">pin this for later</span>
</button>
</div>@import "tailwindcss";
@theme {
--color-tb33-bg: #dfd8c8;
--color-tb33-bg: oklch(0.88 0.022 88);
--color-tb33-tape: #eee2bee6;
--color-tb33-tape-2: #decea4eb;
--color-tb33-ink: #33291c;
--color-tb33-ink: oklch(0.27 0.025 75);
--color-tb33-grid: #0000000a;
--font-tb33-hand: "Caveat", ui-rounded, "Comic Sans MS", cursive;
--ease-tb33-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-33 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: repeating-linear-gradient(0deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), repeating-linear-gradient(90deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), var(--color-tb33-bg);
}
/* THE TAPE: translucent base + lengthwise weave (2px and 5px) + diagonal sheen,
then a three-layer mask that tears both ends. Every mask layer needs its own
size and repeat — a missing no-repeat tiles the base and eats the tape. */
.tb-33__tape {
background-color: var(--color-tb33-tape);
background-image: repeating-linear-gradient(90deg, rgba(255,255,255,.22) 0 1px, transparent 1px 2px), repeating-linear-gradient(90deg, rgba(0,0,0,.045) 0 1px, transparent 1px 5px), linear-gradient(102deg, rgba(255,255,255,.3), transparent 40%, rgba(0,0,0,.07)), linear-gradient(180deg, var(--color-tb33-tape), var(--color-tb33-tape-2));
-webkit-mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
}
@media (prefers-color-scheme: dark) {
.tb-33:not([data-theme="light"]) {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-tape-2: oklch(0.75 0.055 85 / 0.9);
--color-tb33-grid: #ffffff0f;
}
}
.tb-33[data-theme="dark"] {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-grid: #ffffff0f;
}
@media (forced-colors: active) {
.tb-33__tape {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
mask: none;
-webkit-mask: none;
filter: none;
rotate: 0deg;
}
}@import "tailwindcss";
@theme {
--color-tb33-bg: #dfd8c8;
--color-tb33-bg: oklch(0.88 0.022 88);
--color-tb33-tape: #eee2bee6;
--color-tb33-tape-2: #decea4eb;
--color-tb33-ink: #33291c;
--color-tb33-ink: oklch(0.27 0.025 75);
--color-tb33-grid: #0000000a;
--font-tb33-hand: "Caveat", ui-rounded, "Comic Sans MS", cursive;
--ease-tb33-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-33 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: repeating-linear-gradient(0deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), repeating-linear-gradient(90deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), var(--color-tb33-bg);
}
/* THE TAPE: translucent base + lengthwise weave (2px and 5px) + diagonal sheen,
then a three-layer mask that tears both ends. Every mask layer needs its own
size and repeat — a missing no-repeat tiles the base and eats the tape. */
.tb-33__tape {
background-color: var(--color-tb33-tape);
background-image: repeating-linear-gradient(90deg, rgba(255,255,255,.22) 0 1px, transparent 1px 2px), repeating-linear-gradient(90deg, rgba(0,0,0,.045) 0 1px, transparent 1px 5px), linear-gradient(102deg, rgba(255,255,255,.3), transparent 40%, rgba(0,0,0,.07)), linear-gradient(180deg, var(--color-tb33-tape), var(--color-tb33-tape-2));
-webkit-mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
}
@media (prefers-color-scheme: dark) {
.tb-33:not([data-theme="light"]) {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-tape-2: oklch(0.75 0.055 85 / 0.9);
--color-tb33-grid: #ffffff0f;
}
}
.tb-33[data-theme="dark"] {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-grid: #ffffff0f;
}
@media (forced-colors: active) {
.tb-33__tape {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
mask: none;
-webkit-mask: none;
filter: none;
rotate: 0deg;
}
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-tb33-bg: #dfd8c8;
--color-tb33-bg: oklch(0.88 0.022 88);
--color-tb33-tape: #eee2bee6;
--color-tb33-tape-2: #decea4eb;
--color-tb33-ink: #33291c;
--color-tb33-ink: oklch(0.27 0.025 75);
--color-tb33-grid: #0000000a;
--font-tb33-hand: "Caveat", ui-rounded, "Comic Sans MS", cursive;
--ease-tb33-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-33 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: repeating-linear-gradient(0deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), repeating-linear-gradient(90deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), var(--color-tb33-bg);
}
/* THE TAPE: translucent base + lengthwise weave (2px and 5px) + diagonal sheen,
then a three-layer mask that tears both ends. Every mask layer needs its own
size and repeat — a missing no-repeat tiles the base and eats the tape. */
.tb-33__tape {
background-color: var(--color-tb33-tape);
background-image: repeating-linear-gradient(90deg, rgba(255,255,255,.22) 0 1px, transparent 1px 2px), repeating-linear-gradient(90deg, rgba(0,0,0,.045) 0 1px, transparent 1px 5px), linear-gradient(102deg, rgba(255,255,255,.3), transparent 40%, rgba(0,0,0,.07)), linear-gradient(180deg, var(--color-tb33-tape), var(--color-tb33-tape-2));
-webkit-mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
}
@media (prefers-color-scheme: dark) {
.tb-33:not([data-theme="light"]) {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-tape-2: oklch(0.75 0.055 85 / 0.9);
--color-tb33-grid: #ffffff0f;
}
}
.tb-33[data-theme="dark"] {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-grid: #ffffff0f;
}
@media (forced-colors: active) {
.tb-33__tape {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
mask: none;
-webkit-mask: none;
filter: none;
rotate: 0deg;
}
}@import "tailwindcss";
@theme {
--color-tb33-bg: #dfd8c8;
--color-tb33-bg: oklch(0.88 0.022 88);
--color-tb33-tape: #eee2bee6;
--color-tb33-tape-2: #decea4eb;
--color-tb33-ink: #33291c;
--color-tb33-ink: oklch(0.27 0.025 75);
--color-tb33-grid: #0000000a;
--font-tb33-hand: "Caveat", ui-rounded, "Comic Sans MS", cursive;
--ease-tb33-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-33 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: repeating-linear-gradient(0deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), repeating-linear-gradient(90deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), var(--color-tb33-bg);
}
/* THE TAPE: translucent base + lengthwise weave (2px and 5px) + diagonal sheen,
then a three-layer mask that tears both ends. Every mask layer needs its own
size and repeat — a missing no-repeat tiles the base and eats the tape. */
.tb-33__tape {
background-color: var(--color-tb33-tape);
background-image: repeating-linear-gradient(90deg, rgba(255,255,255,.22) 0 1px, transparent 1px 2px), repeating-linear-gradient(90deg, rgba(0,0,0,.045) 0 1px, transparent 1px 5px), linear-gradient(102deg, rgba(255,255,255,.3), transparent 40%, rgba(0,0,0,.07)), linear-gradient(180deg, var(--color-tb33-tape), var(--color-tb33-tape-2));
-webkit-mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
}
@media (prefers-color-scheme: dark) {
.tb-33:not([data-theme="light"]) {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-tape-2: oklch(0.75 0.055 85 / 0.9);
--color-tb33-grid: #ffffff0f;
}
}
.tb-33[data-theme="dark"] {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-grid: #ffffff0f;
}
@media (forced-colors: active) {
.tb-33__tape {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
mask: none;
-webkit-mask: none;
filter: none;
rotate: 0deg;
}
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Caveat:wght@500;600;700&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Caveat:wght@500;600;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Utilities: all three rotations, the lift, three filter-shadow states, the label's counter-rotation, the dashed focus ring. CSS: the weave (four layers) and the torn-end mask (three layers).
- Rotation as a utility and texture as CSS is the same split as demos 21–25, and by now it is a rule rather than a judgement call. The useful test: could this value be wrong in a way a designer would notice and fix? A 1.7° tilt, yes. A 5px weave period, no.
- The dark branch keeps the tape translucent by re-declaring it in
oklch(... / 0.88)rather than swapping to an opaque hex. Translucency is the whole reason the object reads as tape, so it survives theming. - A11y fix from the CSS original: the dark branch set
--ink:#2b251b— near-black ink on a translucent pale tape over a near-black page, which measured about 2.4:1 wherever the tape thinned. The port uses one--color-tb33-inkatoklch(0.27 0.025 75)in both schemes, ≈7:1 against the tape in each.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Masking Tape Label Button
Source: https://codefronts.com/components/tailwind-css-buttons/tailwind-masking-tape-label-button/
A strip of drafting tape stuck slightly crooked: translucent so the surface shows through, fibrous weave running lengthwise, ragged torn ends cut by a repeating mask, and a hand-written label. Hover presses the tape flatter; pressing sticks it down.
## HTML
```html
<div class="tb-33 w-full min-h-svh grid place-items-center font-tb33-hand p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="tb-33__tape group cursor-pointer border-0 px-10 py-3.5 rounded-none text-2xl font-semibold tracking-[0.01em] text-tb33-ink -rotate-[1.7deg] drop-shadow-[0_4px_5px_#3c301e47] transition-[rotate,translate,filter] duration-[400ms] ease-tb33-out [-webkit-tap-highlight-color:transparent] hover:-rotate-[0.4deg] hover:-translate-y-0.5 hover:drop-shadow-[0_8px_9px_#3c301e4d] focus-visible:-rotate-[0.4deg] focus-visible:-translate-y-0.5 focus-visible:outline-2 focus-visible:outline-dashed focus-visible:outline-tb33-ink focus-visible:outline-offset-4 active:-rotate-[1.2deg] active:translate-y-px active:drop-shadow-[0_2px_2px_#3c301e4d] disabled:cursor-not-allowed disabled:opacity-60 disabled:drop-shadow-none motion-reduce:transition-none motion-reduce:hover:rotate-0">
<span class="inline-block transition-[rotate] duration-[400ms] ease-tb33-out group-hover:rotate-[0.6deg] group-focus-visible:rotate-[0.6deg] motion-reduce:transition-none">pin this for later</span>
</button>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tb33-bg: #dfd8c8;
--color-tb33-bg: oklch(0.88 0.022 88);
--color-tb33-tape: #eee2bee6;
--color-tb33-tape-2: #decea4eb;
--color-tb33-ink: #33291c;
--color-tb33-ink: oklch(0.27 0.025 75);
--color-tb33-grid: #0000000a;
--font-tb33-hand: "Caveat", ui-rounded, "Comic Sans MS", cursive;
--ease-tb33-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-33 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: repeating-linear-gradient(0deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), repeating-linear-gradient(90deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), var(--color-tb33-bg);
}
/* THE TAPE: translucent base + lengthwise weave (2px and 5px) + diagonal sheen,
then a three-layer mask that tears both ends. Every mask layer needs its own
size and repeat — a missing no-repeat tiles the base and eats the tape. */
.tb-33__tape {
background-color: var(--color-tb33-tape);
background-image: repeating-linear-gradient(90deg, rgba(255,255,255,.22) 0 1px, transparent 1px 2px), repeating-linear-gradient(90deg, rgba(0,0,0,.045) 0 1px, transparent 1px 5px), linear-gradient(102deg, rgba(255,255,255,.3), transparent 40%, rgba(0,0,0,.07)), linear-gradient(180deg, var(--color-tb33-tape), var(--color-tb33-tape-2));
-webkit-mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
}
@media (prefers-color-scheme: dark) {
.tb-33:not([data-theme="light"]) {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-tape-2: oklch(0.75 0.055 85 / 0.9);
--color-tb33-grid: #ffffff0f;
}
}
.tb-33[data-theme="dark"] {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-grid: #ffffff0f;
}
@media (forced-colors: active) {
.tb-33__tape {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
mask: none;
-webkit-mask: none;
filter: none;
rotate: 0deg;
}
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Masking Tape Label Button
Source: https://codefronts.com/components/tailwind-css-buttons/tailwind-masking-tape-label-button/
A strip of drafting tape stuck slightly crooked: translucent so the surface shows through, fibrous weave running lengthwise, ragged torn ends cut by a repeating mask, and a hand-written label. Hover presses the tape flatter; pressing sticks it down.
## HTML
```html
<div class="tb-33 w-full min-h-svh grid place-items-center font-tb33-hand p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="tb-33__tape group cursor-pointer border-0 px-10 py-3.5 rounded-none text-2xl font-semibold tracking-[0.01em] text-tb33-ink -rotate-[1.7deg] drop-shadow-[0_4px_5px_#3c301e47] transition-[rotate,translate,filter] duration-[400ms] ease-tb33-out [-webkit-tap-highlight-color:transparent] hover:-rotate-[0.4deg] hover:-translate-y-0.5 hover:drop-shadow-[0_8px_9px_#3c301e4d] focus-visible:-rotate-[0.4deg] focus-visible:-translate-y-0.5 focus-visible:outline-2 focus-visible:outline-dashed focus-visible:outline-tb33-ink focus-visible:outline-offset-4 active:-rotate-[1.2deg] active:translate-y-px active:drop-shadow-[0_2px_2px_#3c301e4d] disabled:cursor-not-allowed disabled:opacity-60 disabled:drop-shadow-none motion-reduce:transition-none motion-reduce:hover:rotate-0">
<span class="inline-block transition-[rotate] duration-[400ms] ease-tb33-out group-hover:rotate-[0.6deg] group-focus-visible:rotate-[0.6deg] motion-reduce:transition-none">pin this for later</span>
</button>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tb33-bg: #dfd8c8;
--color-tb33-bg: oklch(0.88 0.022 88);
--color-tb33-tape: #eee2bee6;
--color-tb33-tape-2: #decea4eb;
--color-tb33-ink: #33291c;
--color-tb33-ink: oklch(0.27 0.025 75);
--color-tb33-grid: #0000000a;
--font-tb33-hand: "Caveat", ui-rounded, "Comic Sans MS", cursive;
--ease-tb33-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-33 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: repeating-linear-gradient(0deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), repeating-linear-gradient(90deg, var(--color-tb33-grid) 0 1px, transparent 1px 1.75rem), var(--color-tb33-bg);
}
/* THE TAPE: translucent base + lengthwise weave (2px and 5px) + diagonal sheen,
then a three-layer mask that tears both ends. Every mask layer needs its own
size and repeat — a missing no-repeat tiles the base and eats the tape. */
.tb-33__tape {
background-color: var(--color-tb33-tape);
background-image: repeating-linear-gradient(90deg, rgba(255,255,255,.22) 0 1px, transparent 1px 2px), repeating-linear-gradient(90deg, rgba(0,0,0,.045) 0 1px, transparent 1px 5px), linear-gradient(102deg, rgba(255,255,255,.3), transparent 40%, rgba(0,0,0,.07)), linear-gradient(180deg, var(--color-tb33-tape), var(--color-tb33-tape-2));
-webkit-mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
mask: radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y, radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y, linear-gradient(#000, #000) .4rem 0/calc(100% - .8rem) 100% no-repeat;
}
@media (prefers-color-scheme: dark) {
.tb-33:not([data-theme="light"]) {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-tape-2: oklch(0.75 0.055 85 / 0.9);
--color-tb33-grid: #ffffff0f;
}
}
.tb-33[data-theme="dark"] {
--color-tb33-bg: oklch(0.22 0.018 80);
--color-tb33-tape: oklch(0.82 0.05 88 / 0.88);
--color-tb33-grid: #ffffff0f;
}
@media (forced-colors: active) {
.tb-33__tape {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
mask: none;
-webkit-mask: none;
filter: none;
rotate: 0deg;
}
}
```How this works
The torn ends are a three-layer mask pinned left and right, with a solid middle. Both the notch pattern and the calc(100% - .8rem) middle must agree, so the mask stays in the stylesheet with its warning:
mask:
radial-gradient(.22rem .3rem at 0 50%, transparent 96%, #000 0) 0 0/.42rem .5rem repeat-y,
radial-gradient(.22rem .3rem at 100% 50%, transparent 96%, #000 0) 100% 0/.42rem .5rem repeat-y,
linear-gradient(#000,#000) .4rem 0/calc(100% - .8rem) 100% no-repeat;Tape reads as tape because of translucency plus a directional weave: a low-alpha base, a 2px lengthwise repeat, a 5px coarser one, and a broad diagonal sheen. Four layers, one recipe, CSS.
The rotation is the design value, and it is a utility — which matters, because it is the number a designer will actually fiddle with, and because a rotated button has a rotated hit area.
Make it yours
- Tape colour is
--color-tb33-tape; keep alpha between .82 and .92 or it stops looking translucent. - Notch rhythm is the mask's
.42rem .5remtile — smaller reads as a cleaner tear. - Rest rotation beyond 3° starts to look like a mistake rather than a hand.
- Swap Caveat for a marker face if the label needs more weight.
- The stage's graph-paper grid is two repeating gradients; change the 1.75rem pitch to resize the squares.
Gotchas — read before shipping
- Handwriting fonts are low-legibility small. 1.125rem minimum, and never for critical actions.
- A rotated button's hit area rotates too. Keep it small so targets stay predictable.
drop-shadowplus a multi-layer mask is heavy. Once, not on a list.- Translucent controls inherit the background's contrast problems. Test against the lightest thing behind the tape.
- Multi-layer masks need explicit repeat and size per layer, or the base layer tiles and eats the tape.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 120+ | 16.4+ | 128+ | 120+ |
Multi-layer mask shorthand needs Chrome 120 / Safari 15.4 / Firefox 53, with the -webkit- shim in the CSS block. Without it the ends are straight and the tape still works.