Precios neobrutalistas
Tarjetas de color plano con sombra dura, sello inclinado y viñetas cuadradas.
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
/**
* Precios neobrutalistas: tarjetas de colores planos con borde grueso y sombra dura, sello inclinado en la destacada y viñetas cuadradas.
* Al pasar el puntero cada tarjeta se levanta y al presionar el botón se aplasta. Solo CSS.
*
* <BrutalistPricing plans={[{ name: "Pequeño", price: "$99", features: ["1 sitio"], cta: { label: "Lo quiero", href: "/pedir" }, color: "#ffd23f" }]} />
*/
import type { CSSProperties } from "react";
export type BrutalistPlan = {
name: string;
price: string;
period?: string;
features: string[];
cta: { label: string; href: string };
/** Color de fondo de la tarjeta. */
color?: string;
/** Sello inclinado, por ejemplo "Popular". */
stamp?: string;
};
export type BrutalistPricingProps = {
title?: string;
plans?: BrutalistPlan[];
className?: string;
style?: CSSProperties;
};
const CSS = `
.gcpb-root { --gcpb-ink: #111; box-sizing: border-box; padding: clamp(32px, 5vw, 72px) clamp(16px, 4vw, 56px); background: #ecebff; color: var(--gcpb-ink); font-family: inherit;
background-image: radial-gradient(#1111111f 1.5px, transparent 1.6px); background-size: 22px 22px; }
.gcpb-title { margin: 0 auto; max-width: 14ch; font-size: clamp(36px, 6vw, 80px); font-weight: 900; line-height: .92; letter-spacing: -.045em; text-align: center; text-transform: uppercase; text-wrap: balance; }
.gcpb-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 26px; max-width: 1080px; margin: clamp(32px, 5vw, 56px) auto 0; align-items: start; }
.gcpb-card { position: relative; display: flex; flex-direction: column; padding: 28px; border: 3px solid var(--gcpb-ink); border-radius: 18px; background: var(--gcpb-bg, #ffd23f); box-shadow: 8px 8px 0 var(--gcpb-ink); transition: transform .15s ease-out, box-shadow .15s ease-out; }
.gcpb-card:hover { transform: translate(-3px, -3px); box-shadow: 11px 11px 0 var(--gcpb-ink); }
.gcpb-card:nth-child(2) { transform: rotate(-1.2deg); } .gcpb-card:nth-child(2):hover { transform: rotate(-1.2deg) translate(-3px, -3px); }
.gcpb-stamp { position: absolute; top: -20px; right: -14px; padding: 6px 14px; border: 3px solid var(--gcpb-ink); border-radius: 8px; background: #fff; font-size: 14px; font-weight: 900; text-transform: uppercase; transform: rotate(6deg); box-shadow: 3px 3px 0 var(--gcpb-ink); }
.gcpb-card h3 { margin: 0; font-size: 24px; font-weight: 900; text-transform: uppercase; letter-spacing: -.02em; }
.gcpb-price { margin: 14px 0 0; font-size: clamp(54px, 6vw, 76px); font-weight: 900; line-height: .9; letter-spacing: -.06em; }
.gcpb-price small { margin-left: 4px; font-size: 18px; font-weight: 800; letter-spacing: 0; }
.gcpb-card ul { display: grid; gap: 11px; margin: 24px 0 28px; padding: 0; list-style: none; font-size: 16px; font-weight: 700; line-height: 1.35; }
.gcpb-card li { display: flex; gap: 12px; } .gcpb-card li::before { content: ""; flex: none; width: 12px; height: 12px; margin-top: 5px; border: 2.5px solid var(--gcpb-ink); background: #fff; }
.gcpb-cta { display: inline-flex; align-items: center; justify-content: center; min-height: 54px; margin-top: auto; border: 3px solid var(--gcpb-ink); border-radius: 12px; background: #fff; color: var(--gcpb-ink); font-size: 17px; font-weight: 900; text-decoration: none; text-transform: uppercase; box-shadow: 5px 5px 0 var(--gcpb-ink); transition: transform .12s ease-out, box-shadow .12s ease-out; }
.gcpb-cta:hover { transform: translate(-2px, -2px); box-shadow: 7px 7px 0 var(--gcpb-ink); }
.gcpb-cta:active { transform: translate(5px, 5px); box-shadow: 0 0 0 var(--gcpb-ink); }
.gcpb-cta:focus-visible { outline: 3px solid var(--gcpb-ink); outline-offset: 5px; }
@media (prefers-reduced-motion: reduce) { .gcpb-card, .gcpb-cta { transition: none; } }
`;
const DEFAULT_PLANS: BrutalistPlan[] = [
{ name: "Chico", price: "$99", period: "/ mes", color: "#ffd23f", features: ["Un sitio", "Dominio propio", "Soporte por correo"], cta: { label: "Lo quiero", href: "#chico" } },
{ name: "Mediano", price: "$249", period: "/ mes", color: "#ff7ab8", stamp: "Popular", features: ["Hasta cinco sitios", "Cambios ilimitados", "Reunión mensual", "Prioridad en soporte"], cta: { label: "Lo quiero", href: "#mediano" } },
{ name: "Grande", price: "$599", period: "/ mes", color: "#5eead4", features: ["Sitios ilimitados", "Diseño a la medida", "Acompañamiento semanal"], cta: { label: "Hablemos", href: "#grande" } },
];
export function BrutalistPricing({ title = "Elige tu tamaño", plans = DEFAULT_PLANS, className, style }: BrutalistPricingProps) {
return (
<>
<style>{CSS}</style>
<section className={["gcpb-root", className].filter(Boolean).join(" ")} style={style}>
<h2 className="gcpb-title">{title}</h2>
<div className="gcpb-grid">
{plans.map((plan) => (
<article className="gcpb-card" key={plan.name} style={{ ["--gcpb-bg" as string]: plan.color } as CSSProperties}>
{plan.stamp ? <span className="gcpb-stamp">{plan.stamp}</span> : null}
<h3>{plan.name}</h3>
<p className="gcpb-price">{plan.price}{plan.period ? <small>{plan.period}</small> : null}</p>
<ul>{plan.features.map((feature) => <li key={feature}>{feature}</li>)}</ul>
<a className="gcpb-cta" href={plan.cta.href}>{plan.cta.label}</a>
</article>
))}
</div>
</section>
</>
);
}
Úsalo en tu proyecto
Instálalo con la CLI de shadcn.
npx shadcn@latest add https://www.gassierconsulting.com/r/precios-brutalistaEjemplo de uso de Precios neobrutalistas
Después de copiar brutalist-pricing.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.
import { BrutalistPricing } from "./brutalist-pricing";
export default function Ejemplo() {
return <BrutalistPricing title="Ejemplo" />;
}Propiedades de BrutalistPricing
BrutalistPricing acepta 4 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.
| Propiedad | Tipo | Descripción |
|---|---|---|
title? | string | Opcional. |
plans? | BrutalistPlan[] | Opcional. |
className? | string | Opcional. |
style? | CSSProperties | Opcional. |
Personaliza Precios neobrutalistas con variables CSS
Define estas variables en el contenedor o en tu hoja de estilos para cambiar los colores sin tocar el componente. Si no las defines, se usa el valor por defecto.
| Variable | Valor por defecto |
|---|---|
--gcpb-bg | #ffd23f |
Accesibilidad y rendimiento
El archivo tiene 77 líneas (5 KB) y no necesita @keyframes. Esto es lo que hace Precios neobrutalistas por quien lo usa:
- Detecta prefers-reduced-motion y baja o quita el movimiento cuando la persona lo pide.
- Muestra un anillo de foco visible al navegar con teclado (:focus-visible).
Acerca del producto
Una sección de precios neobrutalista: tres tarjetas de colores planos con borde grueso y sombra dura, una ligeramente girada con un sello, viñetas cuadradas y botones que se aplastan al presionar.
Incluye
Una sección completa en un solo archivo React + TypeScript, con los estilos dentro. No usa Tailwind ni bibliotecas externas.
- Color de cada tarjeta configurable
- Sello inclinado opcional (stamp)
- Botones con sombra dura que se aplastan
- Sin JavaScript
Cómo usarlo
Pasa plans con name, price, period, features, cta, color y stamp.