Design System v1.0

NutriGrow Vibrant

Guía de implementación para el equipo de frontend. Tokens, componentes, estados y criterios de accesibilidad listos para React + Tailwind.

WCAG 2.2 AA React + Tailwind 4 componentes Última revisión: 2026-06-16

01Design Tokens — Color

Usa siempre el token semántico, nunca el valor hexadecimal directo en código.

--color-primary #7C61D4

CTAs, links activos, focus rings

--color-primary-dark #5E45B8

Hover sobre primario

--color-primary-bg #F0EDFC

Fondos suaves, chips, badges

--color-secondary #EAAE87

Acciones secundarias, acentos cálidos

--color-success #16A34A

Completado, activo, positivo

--color-warning #D97706

Alertas, pausado, pendiente

--color-danger #DC2626

Errores, eliminaciones, crítico

--color-text #2F281D

Texto principal, headings

02Tipografía

Tres familias con responsabilidades distintas. No mezclar fuera de su rol.

Type Scale 14 / 16 / 18 / 24 / 32 / 40
display-2xl Fascinate · 40px · 400
Registra tu progreso
display-xl Fascinate · 32px · 400
Plan semanal
heading-lg Noto Sans · 24px · 700
Calorías de hoy
body-md Noto Sans · 16px · 400
Registra tu comida y lleva el control de tus macros de forma sencilla.
label-caps Fira Code · 14px · 500
PROTEÍNAS · KG · KCAL

03Espaciado

Escala fija de 8 pasos. Nunca usar valores arbitrarios fuera de esta escala.

--space-1
2px — separación mínima entre texto y ornamento
--space-2
4px — padding interior de chips pequeños
--space-3
8px — gap dentro de un mismo componente
--space-4
12px — padding horizontal de inputs pequeños
--space-5
16px — padding estándar de botones y cards internas
--space-6
24px — padding de sección dentro de una card
--space-7
32px — separación entre secciones de la página
--space-8
48px — margen vertical entre bloques mayores

04Botones

Componente más frecuente de la app. Mínimo 44px de altura para touch (WCAG 2.5.8).

Button 4 variantes · 3 tamaños · 5 estados
Variantes
Tamaños
Estados — Disabled & Loading
Regla Nivel Implementación
Altura mínima de 44px en todos los tamaños MUST min-height: 44px
Focus ring visible con offset de 3px MUST outline: 3px solid var(--color-primary) + outline-offset: 2px
Sólo un botón primary por viewport en pantallas móviles SHOULD Si hay dos acciones primarias, degradar una a ghost
Estado loading debe ocultar el texto del botón MUST Añadir aria-busy="true" y aria-label="Guardando…"
No usar botones con color puro sin texto ni icono NEVER Si sólo hay icono, añadir aria-label descriptivo

05Badges de Estado

Indican el estado del plan nutricional. Solo texto semántico; nunca comunicar estado sólo por color.

Badge 4 estados · Fira Code · dot indicator
Estados del plan Activo Pausado Completado Error de sync

06Inputs de Formulario

Para el registro de comidas, peso y objetivos. Altura mínima 44px. Mensajes de error inline siempre.

Input default · focus · error · disabled
Escribe el nombre tal como aparece en el envase.
g
El valor debe ser mayor que 0.
kcal
Déjalo en blanco para usar el calculado por tu plan.
Cámbialo en Ajustes de cuenta.

07Plan Cards

Elemento central del dashboard. Muestra resumen del plan nutricional del usuario.

💪
Activo
Plan Volumen +
Carlos Méndez · Semana 4 / 12
2.650 kcal/día
185g Proteína
310g Carbos
72g Grasa
Adherencia 87%
🥗
Pausado
Definición Verano
Laura Sanz · Semana 2 / 8
1.900 kcal/día
160g Proteína
180g Carbos
65g Grasa
Adherencia 52%

08Reglas de Accesibilidad

Cada criterio es testable. Si no puedes escribir un test para él, no es una regla.

Criterio Componente Test
Ratio de contraste ≥ 4.5:1 texto sobre fondo Todos axe-core + Storybook
Focus ring visible en todos los interactivos Btn, Input, Plan Card Tab navigation · Cypress
Targets táctiles ≥ 44×44px (WCAG 2.5.8) Btn, Badge clicable Testing Library · getByRole
Estado de error comunicado por texto, no sólo color Input aria-describedby apunta al mensaje
Animaciones desactivables con prefers-reduced-motion Btn hover, Card hover CSS media query presente en build
Labels de formulario siempre visibles (no sólo placeholder) Input form.label + for/id coinciden

09Anti-patrones

Ejemplos de lo que NO hacer — extrae a tickets de deuda técnica si los encuentras.

✕ No hacer

Usar #7C61D4 directamente en un componente en lugar del token var(--color-primary).

Resultado: al cambiar la paleta global, ese componente queda huérfano y hay que cazarlo manualmente.

✓ Hacer

Usar siempre el token semántico: background: var(--color-primary).

Un cambio en :root se propaga a toda la UI de forma predecible.

✕ No hacer

Poner dos botones btn-primary juntos ("Guardar" y "Publicar") con el mismo peso visual.

Genera ambigüedad de acción principal y aumenta tasa de error del usuario.

✓ Hacer

Una acción primary + la secundaria como btn-ghost. Jerarquía visual clara.

El usuario sabe cuál es la acción recomendada sin leer ambos labels.

✕ No hacer

Indicar un estado de error solo cambiando el borde del input a rojo, sin texto explicativo.

Falla WCAG 1.4.1 (uso del color) — usuarios daltónicos no perciben el cambio.

✓ Hacer

Color rojo en borde + icono de error + mensaje de texto con role="alert" inline.

Supera WCAG 1.4.1 y es legible por lectores de pantalla.

10QA Checklist — Code Review

Ejecuta antes de cada PR que toque componentes UI. Falla el PR si algún must falla.

Tokens & CSS
No hay valores hex crudos fuera de :root
Todos los colores referencian var(--color-*)
Espaciados solo usan la escala de tokens
Fuentes cargadas vía Google Fonts o local
Accesibilidad
axe-core 0 violaciones critical/serious
Tab navigation funciona sin ratón
Todos los inputs tienen label visible
Touch targets ≥ 44px (botones e inputs)
Componentes
Botones tienen estado disabled implementado
Inputs muestran error con texto (no solo color)
Cards tienen hover y focus-visible
Badges no comunican info solo por color
Responsive & Perf
Plan cards apilan en mobile (1 col)
prefers-reduced-motion desactiva transiciones
Sin CDN externo en producción (fuentes self-hosted)
No hay 2 btn-primary adyacentes en mobile