⬡ Design System

NutriTrack
Design System

Guía de implementación para equipos de diseño y desarrollo. Componentes, tokens y criterios de accesibilidad WCAG 2.2 AA.

Versión v1.0.0
Fecha Junio 2026
Estilo Modern Professional
Accesibilidad WCAG 2.2 AA
Plataformas Web + Mobile

Tokens de Color

Paleta semántica centralizada. Usar siempre el token; nunca valores hex crudos en componentes.

Intención del diseño: NutriTrack comunica energía vital y confianza profesional. El amarillo primario (#FECE14) activa atención sin saturar; el negro secundario ancla estructura y autoridad. Toda la paleta parte de estos dos polos.

Paleta principal
Primary
--color-primary
#FECE14
Secondary
--color-secondary
#000000
Success
--color-success
#16A34A
Warning
--color-warning
#D97706
Danger
--color-danger
#DC2626
Surface
--color-surface
#FFFFFF
Text
--color-text
#111827
Text Muted
--color-text-muted
#6B7280
Contraste y Accesibilidad
#FECE14
Primary sobre Secondary
Botón primario, texto destacado
12.8:1 AA ✓
Texto
Text sobre Surface
Cuerpo de texto general
16.8:1 AAA ✓
Muted
Text Muted sobre Surface
Metadatos, hints
4.6:1 AA ✓
Texto
Text sobre Primary
Labels sobre fondo amarillo
10.1:1 AAA ✓
Blanco
Blanco sobre Primary
PROHIBIDO — bajo contraste
1.3:1 FAIL ✗

Tipografía

Escala mobile-first compacta. Poppins para todo el producto; IBM Plex Mono para labels, datos y código.

Escala tipográfica
H1 / Display
Poppins 800 · 3rem · 1.1
Progreso del paciente
H2 / Heading
Poppins 700 · 2rem · 1.2
Plan nutricional
H3 / Subheading
Poppins 600 · 1.5rem · 1.3
Seguimiento semanal
H4 / Section
Poppins 600 · 1.25rem · 1.4
Resumen de calorías
Body LG
Poppins 400 · 1.125rem · 1.6
El paciente mantiene un déficit calórico consistente esta semana.
Body MD
Poppins 400 · 1rem · 1.6
Consulta de control programada para el próximo martes a las 10:30h.
Body SM
Poppins 400 · 0.875rem · 1.5
Nota: revisar adherencia al plan en la próxima consulta.
Label / Caps
IBM Plex Mono 500 · 0.75rem · caps
ESTADO ACTUAL · PLAN ACTIVO
Code / Mono
IBM Plex Mono 400 · 0.875rem
BMI: 27.4 | Calorías: 1.850 kcal

Escala de Espaciado

Sistema modular basado en múltiplos de 4px. Usar siempre tokens; nunca valores ad hoc.

--space-1
4px — Separación mínima (iconos inline, dot indicators)
--space-2
8px — Padding de chips, gap de icon+label
--space-3
12px — Padding de botón SM, gap interno de cards
--space-4
16px — Padding de botón MD, padding de inputs
--space-6
24px — Padding de cards, gap entre secciones
--space-8
32px — Margen de secciones, padding de página

Bordes y Sombras

Radios coherentes comunican jerarquía visual. Sombras usadas con moderación para profundidad.

Border Radius
4px --radius-sm
8px --radius-md
12px --radius-lg
full --radius-full
Botones e inputs → radius-sm (4px)
Cards → radius-lg (12px)
Chips/badges → radius-full
Sombras
shadow-sm
shadow-md
shadow-lg
Tarjetas en reposo → shadow-sm
Tarjetas en hover → shadow-md
Modales, dropdowns → shadow-lg

Botones

El botón es la acción principal del sistema. Cuatro variantes, tres tamaños, y todos los estados interactivos.

Variantes
Tamaños
Estados
Especificaciones de Botón
Estado Background Border Texto Regla
Default --color-primary --color-primary --color-secondary MUST
Hover --color-primary-hover --color-primary-hover --color-secondary MUST
Focus-visible --color-primary --color-primary --color-secondary MUST outline 3px + offset 2px
Active --color-primary-dark --color-primary-dark --color-secondary SHOULD
Disabled opacity: 0.4, pointer-events: none, aria-disabled="true" MUST
Loading Spinner 14×14px border, mismos colores que default MUST

Inputs de Formulario

Los formularios son el corazón del flujo de datos clínicos. Cada estado comunica validación de forma inequívoca.

Nombre completo tal como aparece en el expediente.
Calculado según perfil metabólico.
⚠ Introduce un valor numérico válido (ej. 72.5).
✓ Correo verificado correctamente.
Asignado automáticamente. No editable.
Especificaciones de Input
EstadoBorderRing (box-shadow)Comportamiento
Default --color-border 1.5px Ninguno Placeholder visible, cursor text
Focus --color-secondary 1.5px 0 0 0 3px rgba(17,24,39,0.08) MUST focus-visible, no outline nativo
Error --color-danger 1.5px 0 0 0 3px rgba(220,38,38,0.08) Mensaje de error bajo el input, aria-invalid="true"
Success --color-success 1.5px 0 0 0 3px rgba(22,163,74,0.08) Mensaje de confirmación, aria-describedby
Disabled --color-border Ninguno bg-alt, cursor: not-allowed, aria-disabled

Badges y Chips de Estado

Indicadores semánticos de estado. No usar color como único diferenciador; siempre acompañar con texto o icono.

Activo Pendiente Inactivo Alerta Plan Premium
Semántica de estados
ChipUso en NutriTrackToken BackgroundToken Text
Activo Paciente con seguimiento activo, plan vigente #DCFCE7 #15803D
Pendiente Consulta programada, pago pendiente #FEF3C7 #B45309
Inactivo Paciente sin actividad > 30 días --color-bg-alt --color-text-muted
Alerta Objetivo no cumplido, dato fuera de rango #FEE2E2 #B91C1C

Tarjeta de Paciente

Componente central del dashboard. Muestra estado, progreso y próxima cita en una vista compacta y scannable.

MG
María García
HC-2024-0892 · 34 años
Activa
Objetivo de pérdida 73%
LM
Luis Moreno
HC-2025-0214 · 52 años
Pendiente
Objetivo de control 41%
AT
Ana Torres
HC-2023-0567 · 28 años
Alerta
Adherencia al plan 18%
Anatomía de la Tarjeta de Paciente
ElementoToken / EspecificaciónRegla
Barra de acento (top) 3px sólido · color según estado (primary / warning / danger) MUST
Avatar 44×44px, border-radius: 50%, iniciales del paciente, background semántico MUST include aria-label
Nombre font-weight: 700, font-size: 1rem, color: --color-text MUST
Metadatos font-mono, font-size: 0.75rem, color: --color-text-muted SHOULD
Barra de progreso height: 6px, radius-full, color según estado MUST incluir label de porcentaje
Footer border-top: 1px --color-border, padding-top: --space-3 SHOULD
Hover shadow-md, border-color: --color-secondary, translateY(-1px) MUST
Focus-visible outline: 3px --color-primary, outline-offset: 2px MUST

Accesibilidad WCAG 2.2 AA

Cada componente debe satisfacer los criterios siguientes. Son testables en code review.

Criterios de aceptación
CriterioNivelAplicación
Contraste texto normal ≥ 4.5:1 AA Todo el cuerpo de texto
Contraste texto grande ≥ 3:1 AA H1, H2 (≥18pt o 14pt bold)
Focus visible en todos los interactivos AA 2.4.11 Botones, inputs, cards, links
No depender solo de color para el estado AA 1.4.1 Chips, campos de error/success
Labels descriptivos en todos los inputs AA 1.3.1 Formularios de registro y seguimiento
aria-invalid en campos de error AA 4.1.3 Input con estado error
role + aria-label en cards interactivas AA 4.1.2 Patient Card (tabindex, role="button")
Interacción por teclado
ComponenteTeclasComportamiento
BotónEnter / SpaceActivar acción
InputTab / Shift+TabNavegar entre campos
Patient CardEnterAbrir perfil del paciente
FormularioEscapeCancelar / cerrar modal
TodosTabOrden lógico de DOM, nunca trampa de foco

Regla de prioridad: Cuando exista conflicto entre estética y accesibilidad, la accesibilidad prevalece sin excepción. Documentar el conflicto y proponer una alternativa en el PR.


Anti-patrones Prohibidos

Implementaciones incorrectas documentadas. Incluyen guía de migración para código existente inconsistente.

✗ Prohibido
Texto blanco sobre Primary (#FECE14) → contraste 1.3:1. WCAG fail. Usar --color-secondary como texto.
✓ Correcto
Texto negro (#000000) sobre Primary (#FECE14) → contraste 12.8:1. WCAG AAA.
✗ Prohibido
Objetivo no cumplido
Solo el color indica el error. Usuarios con daltonismo no pueden interpretarlo. Añadir siempre icono o texto semántico.
✓ Correcto
Alerta · Objetivo no cumplido
Color + punto + texto descriptivo. Funciona con y sin visión del color.
✗ Prohibido
Sin indicador de error visible ni aria-invalid. El usuario no sabe qué falló. outline:none elimina el focus ring nativo sin reemplazarlo.
✓ Correcto
⚠ Valor numérico requerido (ej. 72.5)
Border rojo + mensaje de error + aria-invalid + aria-describedby.
✗ Prohibido
Botones con tamaños, radios y padding inconsistentes. No usar valores ad hoc; seguir el sistema de botones.
✓ Correcto
Tokens de tamaño y radio consistentes. Jerarquía visual clara por variante.
Guía de Migración — Código Existente
Patrón incorrecto existenteMigración recomendadaPrioridad
Texto blanco sobre fondo #FECE14 Cambiar color de texto a --color-secondary (#000) P0 — Urgente
outline: none sin focus ring alternativo Añadir :focus-visible { outline: 3px solid var(--color-primary); } P0 — Urgente
Inputs sin label visible (solo placeholder) Añadir <label> vinculado via for / aria-label P1 — Alta
Valores px hardcoded en padding/margin Sustituir por tokens de espaciado (--space-*) P2 — Normal

Checklist de QA

Ejecutar en cada PR que toque componentes de UI. No merguear si algún ítem P0 está sin marcar.

  • Contraste de color verificado
    Todo el texto visible tiene ratio ≥ 4.5:1 (normal) o ≥ 3:1 (grande). Usar WebAIM Contrast Checker.
    a11y P0
  • Focus ring visible en todos los elementos interactivos
    Navegar con Tab en el componente nuevo. Cada elemento focusable debe mostrar outline de 3px #FECE14 o equivalente.
    a11y P0
  • Solo tokens de color, no valores hex crudos
    grep -r "#[0-9A-Fa-f]{6}" src/components/ no debe devolver resultados nuevos.
    código P1
  • Espaciado usando tokens --space-*
    No se aceptan valores de padding/margin fuera de la escala 4/8/12/16/24/32.
    visual P1
  • Todos los inputs tienen label accesible
    <label for="..."> o aria-label o aria-labelledby presentes. Nunca solo placeholder.
    a11y P0
  • Estados de error usan aria-invalid y aria-describedby
    Screen reader debe anunciar el error. Testear con VoiceOver (Mac) o NVDA (Windows).
    a11y P0
  • Botones deshabilitados usan aria-disabled="true" + pointer-events: none
    No usar solo el atributo HTML disabled si el botón es un <a> o div.
    a11y P1
  • Tipografía respeta la escala definida
    No se usan tamaños de fuente fuera de la escala. font-weight limitado a los pesos definidos (100–900).
    visual P2
  • Patient Card incluye aria-label descriptivo
    aria-label="Ver perfil de [Nombre Paciente]". role="button" si es interactiva.
    a11y P1
  • Textos no son ambiguos como etiqueta de acción
    Evitar "Click aquí", "Ver más", "OK" sin contexto. Usar "Ver plan de María García", "Confirmar eliminación".
    contenido P2
  • Componente responsive: probado en 375px y 1440px
    La Patient Card debe mantenerse legible en mobile. Grids deben colapsar correctamente.
    visual P1
  • Iconos decorativos tienen aria-hidden="true"
    Iconos que acompañan texto deben ser opacos para screen readers.
    a11y P1

Versión y mantenimiento: Este documento se considera fuente de verdad a partir de v1.0.0. Cualquier desviación acordada debe documentarse en el CHANGELOG del design system antes de implementarse en producción. Contacto: equipo de diseño + #design-system en Slack.