Pular para o conteúdo
Biblioteca BTN-03

Botão cool

Botão de degradê vertical com borda inferior dupla e anel interno branco; clareia no hover e escurece ao apertar.

usa o BTN-03
abrir sozinho ↗
Código
BTN-03 · alias botao-cool
Função
Botão
Fonte
21st.dev · button.tsx — variante cool
Recebido
06/10/2026
Status
acervo
Licença
não verificada

O código

botao-cool.css + markup.html 72 linhas · 2 arquivo(s) numa caixa só
/* ===== botao-cool.css ============================================================== */

/* BTN-03 · Botão cool — reescrito do original do 21st.dev sem React, sem Tailwind e sem cva.
   Degradê vertical, borda inferior dupla, anel interno branco e brilho que responde ao toque.

   O efeito inteiro é de FILTRO, não de cor: o hover clareia (brightness 1.1) e o apertar escurece
   (0.9), sobre a mesma pintura. É por isso que ele funciona em qualquer cor que você declarar —
   troque --c-cool-base e o resto acompanha.

   Duas coisas que o original só tinha em Tailwind v4 e aqui são explícitas:
   `bg-linear-to-t` (degradê para cima) e `inset-shadow-*` (sombra interna). Em Tailwind v3 essas
   classes não existem, e o degradê do original simplesmente não aparece. */
.c-botao-cool {
  --c-cool-base: #e8ad32;          /* o âmbar do IDV; troque e o botão inteiro muda */
  --c-cool-topo: color-mix(in srgb, var(--c-cool-base) 85%, transparent);
  --c-cool-tinta: #171717;
  --c-cool-linha: rgba(9, 9, 11, .40);
  --c-cool-anel: rgba(255, 255, 255, .25);
  --c-cool-raio: 6px;
  --c-cool-altura: 36px;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: var(--c-cool-altura);
  padding: 0 16px;
  /* para o topo: a base fica embaixo e a versão mais clara em cima */
  background-image: linear-gradient(to top, var(--c-cool-base), var(--c-cool-topo));
  color: var(--c-cool-tinta);
  border: 1px solid var(--c-cool-linha);
  border-bottom-width: 2px;        /* a borda inferior dupla é o que dá o "assentado" */
  border-radius: var(--c-cool-raio);
  /* o anel interno branco por cima da pintura, e a sombra na cor do próprio botão */
  box-shadow: inset 0 0 0 1px var(--c-cool-anel),
              0 4px 6px -1px color-mix(in srgb, var(--c-cool-base) 20%, transparent);
  font: 500 14px/1 inherit;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: filter .2s ease;
}
.c-botao-cool:hover { filter: brightness(1.1); }
.c-botao-cool:active { filter: brightness(.9); }
.c-botao-cool[disabled], .c-botao-cool[aria-disabled="true"] { opacity: .5; pointer-events: none; }
.c-botao-cool svg { width: 16px; height: 16px; flex: none; pointer-events: none; }

/* tamanhos do original */
.c-botao-cool--p { --c-cool-altura: 32px; padding: 0 12px; font-size: 12px; }
.c-botao-cool--g { --c-cool-altura: 40px; padding: 0 32px; }
.c-botao-cool--icone { --c-cool-altura: 36px; width: 36px; padding: 0; }

/* color-mix é recente: sem ele o topo do degradê some e fica cor chapada, que é degradação
   aceitável. Quem precisar de suporte velho declara --c-cool-topo à mão. */
@supports not (color: color-mix(in srgb, red, blue)) {
  .c-botao-cool { --c-cool-topo: var(--c-cool-base); }
}
@media (prefers-reduced-motion: reduce) { .c-botao-cool { transition: none; } }


/* ===== markup.html ================================================================= */

<!-- BTN-03 · Botão cool. Troque --c-cool-base e o botão inteiro muda de cor: o hover e o
     apertar são filtros sobre a mesma pintura, não cores novas. -->
<button type="button" class="c-botao-cool">Reservar</button>

<button type="button" class="c-botao-cool c-botao-cool--g" style="--c-cool-base:#35c46f;--c-cool-tinta:#0a0a0a">
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
  Confirmar
</button>

<a href="#" class="c-botao-cool c-botao-cool--p" style="--c-cool-base:#ebebeb">Saiba mais</a>

Já rodou em

Ainda não rodou em peça publicada.

Exige

  • react
  • @radix-ui/react-slot (Slot, para o asChild)
  • class-variance-authority (cva)
  • cn (clsx + tailwind-merge)
  • Tailwind v4 — bg-linear-to-t e inset-shadow-* não existem em v3

Como se configura

  • --c-cool-base
  • --c-cool-topo
  • --c-cool-tinta
  • --c-cool-linha
  • --c-cool-anel
  • --c-cool-raio
  • --c-cool-altura

A ficha

O que o 21st.dev entregou

Veio num arquivo com TRÊS componentes. O mesmo .tsx traz o Button (shadcn padrão, com a variante cool), o LiquidButton e o MetalButton. O original/ de cada um dos três é esse arquivo inteiro, igual — é o que foi colado, e cortá-lo seria editar o original.

Três defeitos do arquivo como veio, nenhum corrigido em original/:

  • O export { Button, buttonVariants, liquidbuttonVariants, LiquidButton } aparece antes de liquidbuttonVariants e LiquidButton serem declarados. Funciona por hoisting de export em ESM, mas é artefato de cópia, não escolha.
  • O MetalButton não entra nesse export: tem o próprio export const. E GlassFilter, ShineEffect, colorVariants e metalButtonVariants não são exportados — quem copiar só o LiquidButton leva o GlassFilter junto sem perceber.
  • bg-linear-to-t e inset-shadow-2xs (na variante cool) são classes do Tailwind v4. Em v3 elas não existem, e o degradê do botão simplesmente não aparece.

O componente

Dependências: react, @radix-ui/react-slot, class-variance-authority, cn, e Tailwind v4 — a variante cool usa bg-linear-to-t e inset-shadow-*, que não existem em v3.

Props: variant (7 valores), size (4), asChild (troca o <button> pelo filho, via Slot), mais tudo o que um <button> aceita.

O que faz a variante cool — e é ela que dá nome ao componente:

CamadaO quê
Pinturadegradê para cima, da cor primária (embaixo) à primária a 85% (em cima)
Borda1 px em zinc-950/40, com a inferior em 2 px — é o que assenta o botão
Anelring-1 ring-inset ring-white/25 — a linha branca por dentro da borda
Sombrashadow-md na cor do próprio botão, a 20%
Hoverbrightness(1.1) em 200 ms
Apertarbrightness(0.9)

Tamanho em repouso: 36 px de altura (h-9), 16 px de lateral, raio 6 px, texto de 14 px, peso 500.

A escolha que vale copiar: o estado não troca cor, troca filtro. Por isso o mesmo CSS serve a qualquer cor sem recalcular hover e active — e é o que a adaptação transformou numa variável só.


O que a adaptação da OCTA mudou

  • O efeito virou uma variável: troque --c-cool-base e o botão inteiro muda, porque hover e active são filtro sobre a mesma pintura, não cores novas.
  • As sete variantes do cva saíram. As seis genéricas (default, outline, ghost, link, secondary, destructive) são shadcn padrão e não são o que faz este botão; ficou a cool, que é.
  • bg-linear-to-t e inset-shadow-* viraram linear-gradient(to top, …) e box-shadow: inset … explícitos — funcionam em qualquer lugar, não só em Tailwind v4.
  • color-mix() calcula o topo do degradê a partir da base; sem suporte, degrada para cor chapada em vez de sumir.

Lacunas do original

  • Sem aria-pressed ou aria-busy: o componente não tem estado de carregando, só disabled.
  • O focus-visible do original é ring-1, de 1 px — fino demais para o mínimo de visibilidade de foco. A adaptação não herdou esse valor.
  • As outras seis variantes do cva dependem dos tokens de tema do shadcn (primary, accent, muted): fora de um projeto shadcn elas não pintam nada.