Ir al contenido
Evaluar mi proyecto
Componentes · TarjetasDisponible

Tarjeta de entrada perforada

Entrada editorial con talón perforado, fecha, código y acción; el código de barras es una muestra decorativa.

24 OCT · 18:00

Diseño en movimiento

Sesión online

Reservar mi lugar
DSN-024Entrada de muestra

Código completo

Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.

tarjeta-ticket.tsx87 líneas
Descargar
"use client";

import { type CSSProperties } from "react";

/** Tarjeta de entrada perforada. React + TypeScript, sin dependencias. Personaliza con variables --gcxk-*. */
export type TarjetaTicketProps = {
  title?: string;
  date?: string;
  location?: string;
  code?: string;
  href?: string;
  className?: string;
  style?: CSSProperties;
};

const CSS = `
.gcxk-root { box-sizing: border-box; min-width: 0; max-width: 100%; color: var(--gcxk-fg, #202421); font: 400 15px/1.5 ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
.gcxk-root *, .gcxk-root *::before, .gcxk-root *::after { box-sizing: border-box; }
.gcxk-root button, .gcxk-root input, .gcxk-root textarea, .gcxk-root select { font: inherit; }
.gcxk-root button, .gcxk-root a { -webkit-tap-highlight-color: transparent; }
.gcxk-root :focus-visible { outline: 2px solid var(--gcxk-accent, #25724b); outline-offset: 4px; }
.gcxk-root ::selection { background: var(--gcxk-accent, #25724b); color: #fff; }
.gcxk-root button:disabled { opacity: .5; cursor: not-allowed; }
.gcxk-root svg { flex-shrink: 0; }
@media (prefers-reduced-motion: reduce) { .gcxk-root *, .gcxk-root *::before, .gcxk-root *::after { animation: none !important; transition-duration: .01ms !important; scroll-behavior: auto !important; } }
.gcxk-root { width: 480px; background: var(--gcxk-bg, #f8eecc); display: grid; grid-template-columns: 1fr 110px; border-radius: 14px; box-shadow: 0 12px 30px #452d1b18; overflow: hidden; }
.gcxk-main { padding: 28px; min-width: 0; }
.gcxk-date { font-size: 11px; letter-spacing: .08em; font-variant-numeric: tabular-nums; }
.gcxk-root h3 { font-size: 29px; line-height: 1.1; letter-spacing: -.025em; font-weight: 650; margin: 22px 0 12px; }
.gcxk-root p { margin: 0 0 26px; color: #695c38; font-size: 13px; }
.gcxk-root a { display: inline-flex; align-items: center; gap: 12px; color: #343026; text-underline-offset: 5px; font-size: 13px; font-weight: 600; }
.gcxk-root a svg { transition: transform .25s; }
.gcxk-root a:hover svg { transform: translateX(4px); }
.gcxk-stub { padding: 24px 14px; border-left: 1px dashed #a59263; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 14px; }
.gcxk-bars { display: flex; height: 65px; gap: 2px; }
.gcxk-bars i { background: #3d3728; }
.gcxk-stub span { font: 11px ui-monospace, monospace; }
.gcxk-stub small { color: #655936; font-size: 10px; text-align: center; }
@media(max-width:360px) { .gcxk-root { grid-template-columns:1fr 80px; }
.gcxk-main { padding:20px; }
.gcxk-root h3 { font-size:24px; }
.gcxk-bars { gap:1px; } }`;

export function TarjetaTicket({
  title = "Diseño en movimiento",
  date = "24 OCT · 18:00",
  location = "Sesión online",
  code = "DSN-024",
  href = "#reservar",
  className = "",
  style,
}: TarjetaTicketProps) {
  return (
    <article className={`gcxk-root ${className}`} style={style}>
      <style>{CSS}</style>
      <div className="gcxk-main">
        <span className="gcxk-date">{date}</span>
        <h3>{title}</h3>
        <p>{location}</p>
        <a href={href}>
          Reservar mi lugar
          <svg
            viewBox="0 0 24 24"
            width="18"
            height="18"
            fill="none"
            stroke="currentColor"
            strokeWidth="1.6"
            aria-hidden="true"
          >
            <path d="M5 12h14m-6-6 6 6-6 6" />
          </svg>
        </a>
      </div>
      <div className="gcxk-stub">
        <div className="gcxk-bars" aria-hidden="true">
          {Array.from({ length: 24 }, (_, i) => (
            <i key={i} style={{ width: i % 3 === 0 ? 3 : 1 }} />
          ))}
        </div>
        <span>{code}</span>
        <small>Entrada de muestra</small>
      </div>
    </article>
  );
}

Úsalo en tu proyecto

Instálalo con la CLI de shadcn.

terminal.sh1 líneas
npx shadcn@latest add https://www.gassierconsulting.com/r/tarjeta-ticket

Ejemplo de uso de Tarjeta de entrada perforada

Después de copiar tarjeta-ticket.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.

ejemplo.tsx5 líneas
import { TarjetaTicket } from "./tarjeta-ticket";

export default function Ejemplo() {
  return <TarjetaTicket title="Ejemplo" />;
}

Propiedades de TarjetaTicket

TarjetaTicket acepta 7 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.

PropiedadTipoDescripción
title?stringOpcional.
date?stringOpcional.
location?stringOpcional.
code?stringOpcional.
href?stringOpcional.
className?stringOpcional.
style?CSSPropertiesOpcional.

Personaliza Tarjeta de entrada perforada 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.

VariableValor por defecto
--gcxk-fg#202421
--gcxk-accent#25724b
--gcxk-bg#f8eecc

Accesibilidad y rendimiento

El archivo tiene 87 líneas (4 KB) y no necesita @keyframes. Esto es lo que hace Tarjeta de entrada perforada 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).
  • Expone su estado a tecnologías de apoyo con atributos aria-*.
  • Es un componente de cliente de Next.js: incluye la directiva "use client".
Licencia
MIT
Dependencias
React >=18
Compatibilidad
React 18 y 19 · Next.js (componente de cliente)