Saltar a contenido

Design System y fundamentos de UX/UI

Base visual del storefront: tokens, biblioteca de componentes, reglas responsive y línea base de accesibilidad. Cada tabla lista el estado actual y la regla que rige de acá en más.

Base técnica

Pieza Estado actual Regla
Motor de estilos Tailwind CSS 3.4 · PostCSS · autoprefixer Sin CSS-in-JS ni hojas por componente
Preset base @medusajs/ui-preset Los tokens del preset son la base; lo propio se agrega por theme.extend
Biblioteca de primitivas @medusajs/ui Primera opción para todo control estándar
Primitivas headless @headlessui/react 2.2 · @radix-ui/react-accordion · tailwindcss-radix Solo para lo que @medusajs/ui no cubre
Modo oscuro darkMode: "class" declarado, 0 usos de dark: Fuera de alcance: no escribir variantes dark: hasta que se defina la paleta
CSS global src/styles/globals.css, 184 líneas Solo utilidades transversales y overrides de terceros

Tokens de color

Token Valor Contraste s/ blanco Regla
brand.DEFAULT #ED0000 4.56:1 Único rojo de acción. Texto blanco encima: 4.56:1, cumple AA
brand.hover #B80000 6.91:1 Solo estado hover/pressed
brand.light #FF4D4D 3.27:1 No apto para texto. Solo superficies, bordes y badges
brand.soft #FFF1F1 1.1:1 Solo fondo. Texto encima con text.primary (15.83:1)
brand.foreground #FFFFFF — Texto sobre superficies de marca
text.primary #1A1A1A 17.4:1 Texto por defecto
text.secondary #374151 10.31:1 Texto de apoyo
text.muted #9CA3AF 2.54:1 No apto para texto. Solo placeholders y estados deshabilitados
background.DEFAULT #FFFFFF — Fondo base
background.subtle #F5F5F5 — Superficies elevadas y separadores de sección
grey.0…grey.90 11 pasos, #FFFFFF → #111827 — Escala cerrada. grey.40 y menores no se usan para texto (≤2.54:1)
Variables Algolia --brand-r/g/b + 14 --aa-* en :root Tema del autocomplete. Cambiar el rojo acá y en brand.DEFAULT a la vez

Reglas transversales de color:

  • Prohibido el hex literal en componentes: todo color sale de un token.
  • Umbral mínimo: 4.5:1 en texto normal, 3:1 en texto grande y en bordes de controles.
  • Ningún estado se comunica solo por color (error, seleccionado, disponible).

Tipografía

Conviven dos sistemas de clases. Ambos están vivos y no son intercambiables.

Sistema Origen Clases Usos Regla
txt-* @medusajs/ui-preset 20 (txt-xsmall … txt-xlarge-plus, variantes compact) 83 Sistema vigente. Todo componente nuevo usa estas
text-*-regular / -semi Definidas localmente en globals.css 14 (text-xsmall-regular … text-3xl-semi) 103 Heredadas del starter. No usar en código nuevo; migrar al tocar un componente
Aspecto Estado actual Regla
Familia Inter declarada en fontFamily.sans, sin next/font ni @font-face Cargar por next/font o aceptar el fallback de sistema de forma explícita
Fallback -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Ubuntu, sans-serif Se mantiene
Escala Tailwind por defecto, con 3xl sobrescrito a 2rem No agregar tamaños sueltos: usar la escala de clases
Tamaño mínimo text-xsmall-regular = 10px 10px solo en etiquetas no esenciales; nunca en texto de lectura

Layout, espaciado y forma

Aspecto Estado actual Regla
Contenedor .content-container = max-w-[1440px] w-full mx-auto px-6, 29 usos Contenedor único de página. No definir anchos de página por componente
Anchos sueltos 10 max-w-sm, 4 max-w-4xl, 4 max-w-3xl, y 8 variantes más Permitido dentro de un componente; nunca para el ancho de la página
maxWidth.8xl 100rem Token disponible, sin uso actual
Radios none 0 · soft 2px · base 4px · rounded 8px · large 16px · circle 9999px Escala cerrada; prohibido rounded-[Npx] arbitrario
Espaciado Escala por defecto de Tailwind Sin valores arbitrarios p-[13px]

Reglas responsive

Dos escalas de breakpoints activas al mismo tiempo, con dos valores duplicados.

Breakpoint Valor Origen Usos Regla
2xsmall 320px propio 0 Disponible
xsmall 512px propio 2 Disponible
small 1024px propio 68 Escala vigente
medium 1280px propio 3 Escala vigente
large 1440px propio 0 Escala vigente
xlarge 1680px propio 0 Escala vigente
2xlarge 1920px propio 0 Escala vigente
sm 640px Tailwind 57 No usar en código nuevo
md 768px Tailwind 21 No usar en código nuevo
lg 1024px Tailwind 51 Duplica small — no usar en código nuevo
xl 1280px Tailwind 1 Duplica medium — no usar en código nuevo
2xl 1536px Tailwind 0 No usar
Regla Detalle
Punto de partida Mobile first: los estilos sin prefijo son los de móvil
Corte principal small (1024px) separa móvil/tablet de escritorio
Ancho mínimo soportado 320px
Componentes con variante móvil dedicada mobile-actions, mobile-filter, side-menu, cart-dropdown
Imágenes responsive next/image con sizes declarado
Contenido ancho Tablas y grillas con scroll propio; el body no scrollea en horizontal

Biblioteca de componentes

Primitivas de @medusajs/ui en uso

Primitiva Usos Primitiva Usos
Text 33 Badge 3
clx 27 Toaster 2
Heading 22 Input 2
Button 22 RadioGroup · Checkbox · IconButton · IconBadge · useToggleState · toast 1 c/u
Container 9
Table 8
Label 4

Regla: no reimplementar una primitiva que exista en @medusajs/ui. Si hace falta variar su apariencia, se envuelve; no se copia.

Componentes compartidos propios — modules/common/components

Componente Tipo
input · checkbox · radio · native-select · filter-radio-group Formulario
modal · divider · interactive-link · localized-client-link · CTA Estructura y navegación
product-card · ProductGrid · Hero · HeroSlider · PageHero · RichText Contenido
cart-totals · line-item-options · line-item-price · line-item-unit-price · delete-button Comercio
WhatsAppButton Flotante
Categoría Cantidad Regla
Componentes compartidos 21 Todo lo que use más de un módulo vive acá
Componentes por módulo 172 .tsx en 15 módulos Solo si el uso es de ese dominio
Skeletons 15 Una carga con layout propio exige su skeleton
Iconos propios 18 en common/icons Primero buscar en @medusajs/icons (19 importaciones)
Overlays Dialog de Headless UI en 6 componentes Todo overlay usa Dialog: aporta foco atrapado y cierre por Esc

Movimiento

Aspecto Estado actual Regla
Animaciones definidas 9 (ring, fade-in-right, fade-in-top, fade-out-top, accordion-open, accordion-close, enter, leave, slide-in) Escala cerrada; no agregar keyframes por componente
Duraciones 150ms – 300ms, salvo ring 2.2s y slide-in 1.2s Transiciones de UI ≤ 300ms
prefers-reduced-motion 0 usos Toda animación no esencial se desactiva con motion-reduce:

Línea base de accesibilidad

Objetivo de conformidad: WCAG 2.1 nivel AA.

Señal Medición actual Regla
Idioma del documento <html lang="en"> con contenido en castellano lang="es" — corrección bloqueante
aria-label 24 Todo control sin texto visible lleva nombre accesible
role= 7 Solo cuando el elemento nativo no alcanza
sr-only 3 Texto alternativo para íconos y contexto de enlaces repetidos
htmlFor 4, frente a 21 componentes de formulario Todo input con <label> asociado
tabIndex 0 No se altera el orden de tabulación; tabIndex={-1} solo para foco programático
focus: 41 —
focus-visible: 3 Todo interactivo necesita indicador de foco visible con focus-visible:
outline-none 21 Prohibido sin reemplazo visible en la misma clase
onClick 97 Solo sobre button o a; nunca sobre div o span
<img> nativo 9 en 7 archivos Migrar a next/image (4 archivos ya lo usan)
alt= 19 Obligatorio: descriptivo, o alt="" si es decorativo
Contraste Ver tokens de color 4.5:1 texto · 3:1 UI
data-testid 331 Se mantiene: base de las pruebas end-to-end
Criterio WCAG 2.1 AA Estado Acción
1.1.1 Contenido no textual Parcial Auditar los 9 <img> y los íconos sin sr-only
1.4.3 Contraste mínimo Parcial Retirar text.muted y brand.light de texto
2.1.1 Teclado Sin verificar Recorrido completo de catálogo y checkout con teclado
2.4.7 Foco visible No cumple 21 outline-none contra 3 focus-visible:
3.1.1 Idioma de la página No cumple lang="es"
3.3.2 Etiquetas o instrucciones Parcial Asociar label en todos los formularios
4.1.2 Nombre, función, valor Parcial Revisar los 97 onClick sobre elementos no interactivos

Conflictos abiertos

Conflicto Alcance Regla de convergencia
Dos escalas de breakpoints 129 usos en la escala de Tailwind Migrar a la escala propia al tocar cada componente
Dos sistemas de tipografía 103 usos de las clases locales Migrar a txt-* al tocar cada componente
Dos plantillas de tienda algolia-store-template · instantsearch-store-template Definir cuál queda antes de tocar la grilla
darkMode: "class" sin paleta Config declarada, 0 usos Quitar la config o definir la paleta oscura
Sucursales y teléfono fijos en código WhatsAppButton, disponibilidad, promesa de entrega Fuera del design system: sale a configuración