26 / 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 Pharma Gel Capsule Button
A two-tone gelatin capsule with a wet specular streak, a visible seam where the halves overlap, and a dose of liquid that rises through the shell on hover. Press it and the capsule compresses along its long axis like soft gelatin.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<div class="tb-26 w-full min-h-svh grid place-items-center font-tb26-sans antialiased p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="tb-26__capsule group relative overflow-hidden isolate cursor-pointer min-h-14 pr-9 pl-[calc(var(--tb-26-cap)+1rem)] border-0 rounded-full text-base font-bold tracking-[-0.005em] text-white shadow-[inset_0_-0.35rem_0.7rem_#0000002e,inset_0_0.3rem_0.5rem_#ffffff80,0_14px_26px_-14px_#1e12128c] transition-[scale,translate,box-shadow] duration-300 ease-tb26-out [-webkit-tap-highlight-color:transparent] hover:-translate-y-0.5 active:translate-y-px active:scale-x-[1.03] active:scale-y-90 active:shadow-[inset_0_0.3rem_0.8rem_#00000047] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tb26-body disabled:cursor-not-allowed disabled:grayscale-75 disabled:opacity-70 motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span aria-hidden="true" class="tb-26__dose absolute z-20 inset-y-0 left-0 right-[calc(100%-var(--tb-26-cap))] origin-bottom scale-y-[0.22] shadow-[inset_0_0.1rem_0_#ffffff99,inset_0_-0.3rem_0.5rem_#78380038] transition-[scale] duration-[550ms] ease-tb26-out group-hover:scale-y-[0.84] group-focus-visible:scale-y-[0.84] motion-reduce:transition-none"></span>
<span aria-hidden="true" class="absolute z-30 inset-x-[8%] top-[14%] h-[26%] rounded-full pointer-events-none blur-[1.5px] bg-[linear-gradient(90deg,transparent,rgba(255,255,255,0.85)_20%,rgba(255,255,255,0.5)_58%,transparent)]"></span>
<span class="relative z-40 [text-shadow:0_1px_1px_#50140e66]">Take one daily</span>
</button>
</div><div class="tb-26 w-full min-h-svh grid place-items-center font-tb26-sans antialiased p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="tb-26__capsule group relative overflow-hidden isolate cursor-pointer min-h-14 pr-9 pl-[calc(var(--tb-26-cap)+1rem)] border-0 rounded-full text-base font-bold tracking-[-0.005em] text-white shadow-[inset_0_-0.35rem_0.7rem_#0000002e,inset_0_0.3rem_0.5rem_#ffffff80,0_14px_26px_-14px_#1e12128c] transition-[scale,translate,box-shadow] duration-300 ease-tb26-out [-webkit-tap-highlight-color:transparent] hover:-translate-y-0.5 active:translate-y-px active:scale-x-[1.03] active:scale-y-90 active:shadow-[inset_0_0.3rem_0.8rem_#00000047] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tb26-body disabled:cursor-not-allowed disabled:grayscale-75 disabled:opacity-70 motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span aria-hidden="true" class="tb-26__dose absolute z-20 inset-y-0 left-0 right-[calc(100%-var(--tb-26-cap))] origin-bottom scale-y-[0.22] shadow-[inset_0_0.1rem_0_#ffffff99,inset_0_-0.3rem_0.5rem_#78380038] transition-[scale] duration-[550ms] ease-tb26-out group-hover:scale-y-[0.84] group-focus-visible:scale-y-[0.84] motion-reduce:transition-none"></span>
<span aria-hidden="true" class="absolute z-30 inset-x-[8%] top-[14%] h-[26%] rounded-full pointer-events-none blur-[1.5px] bg-[linear-gradient(90deg,transparent,rgba(255,255,255,0.85)_20%,rgba(255,255,255,0.5)_58%,transparent)]"></span>
<span class="relative z-40 [text-shadow:0_1px_1px_#50140e66]">Take one daily</span>
</button>
</div>@import "tailwindcss";
@theme {
--color-tb26-bg: #eef2f4;
--color-tb26-bg: oklch(0.955 0.006 220);
--color-tb26-cap: #f6f8fa;
--color-tb26-cap: oklch(0.975 0.004 220);
--color-tb26-body: #cf3f33;
--color-tb26-body: oklch(0.54 0.19 28);
--color-tb26-liquid: #ffb347;
--color-tb26-liquid: oklch(0.82 0.14 72);
--color-tb26-liquid-hi: #ffd08f;
--color-tb26-liquid-hi: oklch(0.88 0.1 76);
--color-tb26-liquid-lo: #d98c22;
--color-tb26-liquid-lo: oklch(0.7 0.14 68);
--font-tb26-sans: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb26-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-26 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(34rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb26-bg);
}
/* THE SHELL: two halves plus the seam where the cap slides over the body. Both
layers are driven by --tb-26-cap in four places, so they stay together here. */
.tb-26__capsule {
--tb-26-cap: 5.5rem;
background-image: linear-gradient(90deg, var(--color-tb26-cap) 0 var(--tb-26-cap), var(--color-tb26-body) var(--tb-26-cap) 100%), linear-gradient(90deg, transparent calc(var(--tb-26-cap) - .5rem), rgba(0,0,0,.14) calc(var(--tb-26-cap) - .1rem), rgba(255,255,255,.32) calc(var(--tb-26-cap) + .2rem), transparent calc(var(--tb-26-cap) + .7rem));
}
.tb-26__dose {
background: linear-gradient(180deg, var(--color-tb26-liquid-hi), var(--color-tb26-liquid) 42%, var(--color-tb26-liquid-lo));
}
@media (prefers-color-scheme: dark) {
.tb-26:not([data-theme="light"]) {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
}
.tb-26[data-theme="dark"] {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
@media (forced-colors: active) {
.tb-26__capsule {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-26__capsule span[aria-hidden] {
display: none;
}
}@import "tailwindcss";
@theme {
--color-tb26-bg: #eef2f4;
--color-tb26-bg: oklch(0.955 0.006 220);
--color-tb26-cap: #f6f8fa;
--color-tb26-cap: oklch(0.975 0.004 220);
--color-tb26-body: #cf3f33;
--color-tb26-body: oklch(0.54 0.19 28);
--color-tb26-liquid: #ffb347;
--color-tb26-liquid: oklch(0.82 0.14 72);
--color-tb26-liquid-hi: #ffd08f;
--color-tb26-liquid-hi: oklch(0.88 0.1 76);
--color-tb26-liquid-lo: #d98c22;
--color-tb26-liquid-lo: oklch(0.7 0.14 68);
--font-tb26-sans: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb26-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-26 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(34rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb26-bg);
}
/* THE SHELL: two halves plus the seam where the cap slides over the body. Both
layers are driven by --tb-26-cap in four places, so they stay together here. */
.tb-26__capsule {
--tb-26-cap: 5.5rem;
background-image: linear-gradient(90deg, var(--color-tb26-cap) 0 var(--tb-26-cap), var(--color-tb26-body) var(--tb-26-cap) 100%), linear-gradient(90deg, transparent calc(var(--tb-26-cap) - .5rem), rgba(0,0,0,.14) calc(var(--tb-26-cap) - .1rem), rgba(255,255,255,.32) calc(var(--tb-26-cap) + .2rem), transparent calc(var(--tb-26-cap) + .7rem));
}
.tb-26__dose {
background: linear-gradient(180deg, var(--color-tb26-liquid-hi), var(--color-tb26-liquid) 42%, var(--color-tb26-liquid-lo));
}
@media (prefers-color-scheme: dark) {
.tb-26:not([data-theme="light"]) {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
}
.tb-26[data-theme="dark"] {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
@media (forced-colors: active) {
.tb-26__capsule {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-26__capsule span[aria-hidden] {
display: none;
}
}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-tb26-bg: #eef2f4;
--color-tb26-bg: oklch(0.955 0.006 220);
--color-tb26-cap: #f6f8fa;
--color-tb26-cap: oklch(0.975 0.004 220);
--color-tb26-body: #cf3f33;
--color-tb26-body: oklch(0.54 0.19 28);
--color-tb26-liquid: #ffb347;
--color-tb26-liquid: oklch(0.82 0.14 72);
--color-tb26-liquid-hi: #ffd08f;
--color-tb26-liquid-hi: oklch(0.88 0.1 76);
--color-tb26-liquid-lo: #d98c22;
--color-tb26-liquid-lo: oklch(0.7 0.14 68);
--font-tb26-sans: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb26-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-26 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(34rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb26-bg);
}
/* THE SHELL: two halves plus the seam where the cap slides over the body. Both
layers are driven by --tb-26-cap in four places, so they stay together here. */
.tb-26__capsule {
--tb-26-cap: 5.5rem;
background-image: linear-gradient(90deg, var(--color-tb26-cap) 0 var(--tb-26-cap), var(--color-tb26-body) var(--tb-26-cap) 100%), linear-gradient(90deg, transparent calc(var(--tb-26-cap) - .5rem), rgba(0,0,0,.14) calc(var(--tb-26-cap) - .1rem), rgba(255,255,255,.32) calc(var(--tb-26-cap) + .2rem), transparent calc(var(--tb-26-cap) + .7rem));
}
.tb-26__dose {
background: linear-gradient(180deg, var(--color-tb26-liquid-hi), var(--color-tb26-liquid) 42%, var(--color-tb26-liquid-lo));
}
@media (prefers-color-scheme: dark) {
.tb-26:not([data-theme="light"]) {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
}
.tb-26[data-theme="dark"] {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
@media (forced-colors: active) {
.tb-26__capsule {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-26__capsule span[aria-hidden] {
display: none;
}
}@import "tailwindcss";
@theme {
--color-tb26-bg: #eef2f4;
--color-tb26-bg: oklch(0.955 0.006 220);
--color-tb26-cap: #f6f8fa;
--color-tb26-cap: oklch(0.975 0.004 220);
--color-tb26-body: #cf3f33;
--color-tb26-body: oklch(0.54 0.19 28);
--color-tb26-liquid: #ffb347;
--color-tb26-liquid: oklch(0.82 0.14 72);
--color-tb26-liquid-hi: #ffd08f;
--color-tb26-liquid-hi: oklch(0.88 0.1 76);
--color-tb26-liquid-lo: #d98c22;
--color-tb26-liquid-lo: oklch(0.7 0.14 68);
--font-tb26-sans: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb26-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-26 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(34rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb26-bg);
}
/* THE SHELL: two halves plus the seam where the cap slides over the body. Both
layers are driven by --tb-26-cap in four places, so they stay together here. */
.tb-26__capsule {
--tb-26-cap: 5.5rem;
background-image: linear-gradient(90deg, var(--color-tb26-cap) 0 var(--tb-26-cap), var(--color-tb26-body) var(--tb-26-cap) 100%), linear-gradient(90deg, transparent calc(var(--tb-26-cap) - .5rem), rgba(0,0,0,.14) calc(var(--tb-26-cap) - .1rem), rgba(255,255,255,.32) calc(var(--tb-26-cap) + .2rem), transparent calc(var(--tb-26-cap) + .7rem));
}
.tb-26__dose {
background: linear-gradient(180deg, var(--color-tb26-liquid-hi), var(--color-tb26-liquid) 42%, var(--color-tb26-liquid-lo));
}
@media (prefers-color-scheme: dark) {
.tb-26:not([data-theme="light"]) {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
}
.tb-26[data-theme="dark"] {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
@media (forced-colors: active) {
.tb-26__capsule {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-26__capsule span[aria-hidden] {
display: none;
}
}<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=DM+Sans: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=DM+Sans:wght@500;600;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- Utilities: the dose's rise (origin, both scales, the transition), the meniscus and depth shadows, the specular streak with its blur, the compression press, every state. CSS: the two-layer shell (halves + seam) and the dose's own fill gradient, both because they read
--tb-26-capor three liquid tokens at once. scale-y-[0.22] → scale-y-[0.84]as separate-axis utilities is clearer than the CSSscale:1 .22, which is easy to misread. Same for the press:scale-x-[1.03] scale-y-90states "wider and shorter" explicitly.- Asymmetric padding (
pl-[calc(var(--tb-26-cap)+1rem)] pr-9) is an accessibility decision disguised as layout: it puts the label on the saturated half, away from the white streak. - A11y fix from the CSS original:
--bodywasoklch(0.58 0.19 28)and the label pure white — about 4.1:1, just under the minimum for 16px bold. The port darkens the body half to0.54(≈4.8:1). The capsule looks the same; the label is now legible to a WCAG checker as well as to the eye.
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 Pharma Gel Capsule Button
Source: https://codefronts.com/components/tailwind-css-buttons/tailwind-pharma-gel-capsule-button/
A two-tone gelatin capsule with a wet specular streak, a visible seam where the halves overlap, and a dose of liquid that rises through the shell on hover. Press it and the capsule compresses along its long axis like soft gelatin.
## HTML
```html
<div class="tb-26 w-full min-h-svh grid place-items-center font-tb26-sans antialiased p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="tb-26__capsule group relative overflow-hidden isolate cursor-pointer min-h-14 pr-9 pl-[calc(var(--tb-26-cap)+1rem)] border-0 rounded-full text-base font-bold tracking-[-0.005em] text-white shadow-[inset_0_-0.35rem_0.7rem_#0000002e,inset_0_0.3rem_0.5rem_#ffffff80,0_14px_26px_-14px_#1e12128c] transition-[scale,translate,box-shadow] duration-300 ease-tb26-out [-webkit-tap-highlight-color:transparent] hover:-translate-y-0.5 active:translate-y-px active:scale-x-[1.03] active:scale-y-90 active:shadow-[inset_0_0.3rem_0.8rem_#00000047] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tb26-body disabled:cursor-not-allowed disabled:grayscale-75 disabled:opacity-70 motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span aria-hidden="true" class="tb-26__dose absolute z-20 inset-y-0 left-0 right-[calc(100%-var(--tb-26-cap))] origin-bottom scale-y-[0.22] shadow-[inset_0_0.1rem_0_#ffffff99,inset_0_-0.3rem_0.5rem_#78380038] transition-[scale] duration-[550ms] ease-tb26-out group-hover:scale-y-[0.84] group-focus-visible:scale-y-[0.84] motion-reduce:transition-none"></span>
<span aria-hidden="true" class="absolute z-30 inset-x-[8%] top-[14%] h-[26%] rounded-full pointer-events-none blur-[1.5px] bg-[linear-gradient(90deg,transparent,rgba(255,255,255,0.85)_20%,rgba(255,255,255,0.5)_58%,transparent)]"></span>
<span class="relative z-40 [text-shadow:0_1px_1px_#50140e66]">Take one daily</span>
</button>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tb26-bg: #eef2f4;
--color-tb26-bg: oklch(0.955 0.006 220);
--color-tb26-cap: #f6f8fa;
--color-tb26-cap: oklch(0.975 0.004 220);
--color-tb26-body: #cf3f33;
--color-tb26-body: oklch(0.54 0.19 28);
--color-tb26-liquid: #ffb347;
--color-tb26-liquid: oklch(0.82 0.14 72);
--color-tb26-liquid-hi: #ffd08f;
--color-tb26-liquid-hi: oklch(0.88 0.1 76);
--color-tb26-liquid-lo: #d98c22;
--color-tb26-liquid-lo: oklch(0.7 0.14 68);
--font-tb26-sans: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb26-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-26 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(34rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb26-bg);
}
/* THE SHELL: two halves plus the seam where the cap slides over the body. Both
layers are driven by --tb-26-cap in four places, so they stay together here. */
.tb-26__capsule {
--tb-26-cap: 5.5rem;
background-image: linear-gradient(90deg, var(--color-tb26-cap) 0 var(--tb-26-cap), var(--color-tb26-body) var(--tb-26-cap) 100%), linear-gradient(90deg, transparent calc(var(--tb-26-cap) - .5rem), rgba(0,0,0,.14) calc(var(--tb-26-cap) - .1rem), rgba(255,255,255,.32) calc(var(--tb-26-cap) + .2rem), transparent calc(var(--tb-26-cap) + .7rem));
}
.tb-26__dose {
background: linear-gradient(180deg, var(--color-tb26-liquid-hi), var(--color-tb26-liquid) 42%, var(--color-tb26-liquid-lo));
}
@media (prefers-color-scheme: dark) {
.tb-26:not([data-theme="light"]) {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
}
.tb-26[data-theme="dark"] {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
@media (forced-colors: active) {
.tb-26__capsule {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-26__capsule span[aria-hidden] {
display: none;
}
}
```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 Pharma Gel Capsule Button
Source: https://codefronts.com/components/tailwind-css-buttons/tailwind-pharma-gel-capsule-button/
A two-tone gelatin capsule with a wet specular streak, a visible seam where the halves overlap, and a dose of liquid that rises through the shell on hover. Press it and the capsule compresses along its long axis like soft gelatin.
## HTML
```html
<div class="tb-26 w-full min-h-svh grid place-items-center font-tb26-sans antialiased p-[clamp(1.5rem,6vw,4rem)]">
<button type="button" class="tb-26__capsule group relative overflow-hidden isolate cursor-pointer min-h-14 pr-9 pl-[calc(var(--tb-26-cap)+1rem)] border-0 rounded-full text-base font-bold tracking-[-0.005em] text-white shadow-[inset_0_-0.35rem_0.7rem_#0000002e,inset_0_0.3rem_0.5rem_#ffffff80,0_14px_26px_-14px_#1e12128c] transition-[scale,translate,box-shadow] duration-300 ease-tb26-out [-webkit-tap-highlight-color:transparent] hover:-translate-y-0.5 active:translate-y-px active:scale-x-[1.03] active:scale-y-90 active:shadow-[inset_0_0.3rem_0.8rem_#00000047] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tb26-body disabled:cursor-not-allowed disabled:grayscale-75 disabled:opacity-70 motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span aria-hidden="true" class="tb-26__dose absolute z-20 inset-y-0 left-0 right-[calc(100%-var(--tb-26-cap))] origin-bottom scale-y-[0.22] shadow-[inset_0_0.1rem_0_#ffffff99,inset_0_-0.3rem_0.5rem_#78380038] transition-[scale] duration-[550ms] ease-tb26-out group-hover:scale-y-[0.84] group-focus-visible:scale-y-[0.84] motion-reduce:transition-none"></span>
<span aria-hidden="true" class="absolute z-30 inset-x-[8%] top-[14%] h-[26%] rounded-full pointer-events-none blur-[1.5px] bg-[linear-gradient(90deg,transparent,rgba(255,255,255,0.85)_20%,rgba(255,255,255,0.5)_58%,transparent)]"></span>
<span class="relative z-40 [text-shadow:0_1px_1px_#50140e66]">Take one daily</span>
</button>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tb26-bg: #eef2f4;
--color-tb26-bg: oklch(0.955 0.006 220);
--color-tb26-cap: #f6f8fa;
--color-tb26-cap: oklch(0.975 0.004 220);
--color-tb26-body: #cf3f33;
--color-tb26-body: oklch(0.54 0.19 28);
--color-tb26-liquid: #ffb347;
--color-tb26-liquid: oklch(0.82 0.14 72);
--color-tb26-liquid-hi: #ffd08f;
--color-tb26-liquid-hi: oklch(0.88 0.1 76);
--color-tb26-liquid-lo: #d98c22;
--color-tb26-liquid-lo: oklch(0.7 0.14 68);
--font-tb26-sans: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
--ease-tb26-out: cubic-bezier(0.16, 1, 0.3, 1);
}
.tb-26 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
background: radial-gradient(34rem 20rem at 50% 40%, #ffffff, transparent 70%), var(--color-tb26-bg);
}
/* THE SHELL: two halves plus the seam where the cap slides over the body. Both
layers are driven by --tb-26-cap in four places, so they stay together here. */
.tb-26__capsule {
--tb-26-cap: 5.5rem;
background-image: linear-gradient(90deg, var(--color-tb26-cap) 0 var(--tb-26-cap), var(--color-tb26-body) var(--tb-26-cap) 100%), linear-gradient(90deg, transparent calc(var(--tb-26-cap) - .5rem), rgba(0,0,0,.14) calc(var(--tb-26-cap) - .1rem), rgba(255,255,255,.32) calc(var(--tb-26-cap) + .2rem), transparent calc(var(--tb-26-cap) + .7rem));
}
.tb-26__dose {
background: linear-gradient(180deg, var(--color-tb26-liquid-hi), var(--color-tb26-liquid) 42%, var(--color-tb26-liquid-lo));
}
@media (prefers-color-scheme: dark) {
.tb-26:not([data-theme="light"]) {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
}
.tb-26[data-theme="dark"] {
--color-tb26-bg: oklch(0.18 0.008 220);
--color-tb26-cap: oklch(0.92 0.008 220);
--color-tb26-body: oklch(0.5 0.18 28);
}
@media (forced-colors: active) {
.tb-26__capsule {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
box-shadow: none;
}
.tb-26__capsule span[aria-hidden] {
display: none;
}
}
```How this works
The dose has square corners on purpose. It is a plain rectangle anchored to the cap end; the capsule's own overflow-hidden rounded-full clips it, so the liquid takes the exact shape of the rounded end. Round the dose itself and you get a second pill inside a pill — the classic version of this mistake.
class="absolute inset-y-0 left-0 right-[calc(100%-var(--tb-26-cap))]
origin-bottom scale-y-[0.22] group-hover:scale-y-[0.84]"The two halves and the seam are one background pair — a hard-stop gradient at the cap width, plus a narrow overlap band of dark-then-light that reads as the join. Both stay in the CSS block: they are driven by --tb-26-cap in four places, and an arbitrary utility repeating that variable four times is strictly worse.
The label sits on the saturated half. Not decoration — a white specular streak over the pale half destroys text contrast, so the padding is asymmetric by design.
Make it yours
- Recolour the halves independently with
--color-tb26-capand--color-tb26-body; one light, one saturated is the pharmacy look. - Rest level is the dose's base
scale-y-[0.22]: a part-dose.0.84is nearly full. - Remove the seam layer from the CSS for a single-piece softgel.
- Matte gelcap: raise
blur-[1.5px]. Hard acrylic: drop it to zero. - Cap width is one variable,
--tb-26-cap, and the seam follows it.
Gotchas — read before shipping
- Hard-stop gradients at exactly 50% shimmer on fractional-DPR displays. The seam is offset by a few tenths of a percent for that reason.
- Non-uniform scale distorts text. Keep the label in its own child with a counter-scale if you push compression past 0.9.
- Don't round the liquid layer. Let the parent's clip shape it.
rounded-fullplusoverflow-hiddenclips inset rings — keep focus onoutline-*.- Anything resembling medication needs care in production. Don't imply dosage with a decorative button.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
All gradients, filters and individual transform utilities here are baseline below Tailwind v4's own floor.