DSPC Design System

UX
Patterns.

Reglas de comportamiento que viven encima de los componentes. Definen cuando usar que, en que orden, y con que copy. Un componente sin patron es una pieza suelta.

App (B2C) + Cloud (B2B) Documento vivo
01 — Feedback

Loading.

La percepcion de velocidad es mas importante que la velocidad real. Skeleton siempre gana sobre spinner. Spinner solo cuando no hay forma de anticipar el layout.

Arbol de decision
¿Se conoce el layout del contenido que viene?
Si → Skeleton No → Spinner
¿La carga tarda menos de 200ms?
Si → No mostrar nada No → Mostrar feedback
¿Es una accion del usuario (submit, save)?
Si → Boton disabled + "Procesando..." No → Skeleton / spinner silencioso
¿Tarda mas de 5 segundos?
Si → Skeleton + texto contextual Texto: "Cargando pedidos..." / "Conectando..."
Escenarios DSPC
App B2C
Carga del catalogo.
El usuario abre la seccion de catalogo. El layout es conocido: grid de product cards.
Componente: Skeleton card × 6 (shimmer)
Duracion visible: 200ms delay, luego skeleton hasta carga
Texto: Ninguno (el skeleton comunica suficiente)
Error fallback: Si falla despues de 10s → Empty state "Error al cargar" con boton "Reintentar"
Cloud B2B
Tabla de pedidos.
El administrador entra al dashboard. La tabla de pedidos es la vista principal.
Componente: Skeleton row × 5 (con avatar placeholder)
Duracion visible: 200ms delay, luego skeleton
Texto: Solo si > 5s: "Cargando pedidos..."
Error fallback: Si falla → Empty state "Error al cargar" + toast "No se pudo conectar"
App + Cloud
Confirmar pedido (submit).
El usuario pulsa "Confirmar pedido". Es una accion con consecuencias.
Componente: Boton pasa a estado disabled + spinner inline
Copy del boton: "Confirmando..." (no "Procesando" — usar el verbo de la accion)
Exito: Toast success "Pedido PED-08431 confirmado" + redirigir a detalle
Error: Toast error "No se pudo confirmar. Intenta de nuevo." + boton vuelve a activo
Reglas
— SI

Skeleton para listas, grids, tablas, cards — cualquier layout predecible. Minimo 200ms de delay antes de mostrar (evitar flash).

— SI

Spinner inline en botones durante submit. El boton se deshabilita y cambia su copy al gerundio: "Guardando...", "Eliminando...", "Confirmando..."

— NO

Nunca un spinner full-page centrado. Eso bloquea la interfaz y comunica que algo salio mal. El usuario debe poder navegar mientras carga.

— NO

Nunca mostrar loading si la carga tarda < 200ms. El flash del skeleton es peor que la espera. Usa un delay programatico.

02 — Feedback

Error handling.

Todo error tiene un tipo, un nivel de severidad y un copy canonico. El usuario nunca debe ver un error tecnico crudo. Cada error sugiere una accion concreta.

Arbol de decision
¿El error es de un campo de formulario?
Si → Inline debajo del campo No → Siguiente pregunta
¿Es una accion que fallo (submit, save, delete)?
Si → Toast error + boton vuelve a activo No → Siguiente pregunta
¿Es un error de pagina completa (404, 500, offline)?
Si → Error page dedicada No → Siguiente pregunta
¿Es un error de carga de datos parcial?
Si → Empty state "Error al cargar" en la zona afectada Nunca reemplazar toda la pagina si solo fallo una seccion
Niveles de error
Codigo Tipo Componente Copy canonico
Validacion Campo invalido Inline error (debajo del campo) "Este campo es obligatorio" / "Formato invalido" / "El RFC debe tener 12 o 13 caracteres"
400 Solicitud incorrecta Toast error "No se pudo completar la accion. Revisa los datos e intenta de nuevo."
401 No autenticado Redirigir a login "Tu sesion expiro. Inicia sesion de nuevo."
403 Sin permisos Empty state "Sin acceso" "No tienes permisos para ver esta seccion. Contacta al administrador."
404 No encontrado Error page 404 "Pagina no encontrada. La URL que buscas no existe o fue movida."
408 / timeout Timeout Toast error + retry "La solicitud tardo demasiado. Intenta de nuevo."
429 Rate limit Toast warning "Demasiadas solicitudes. Espera un momento e intenta de nuevo."
500 Error del servidor Error page 500 o toast "Algo salio mal de nuestro lado. Estamos trabajando en ello."
503 Mantenimiento Error page mantenimiento "Estamos actualizando el sistema. Regresa en aproximadamente 30 minutos."
Offline Sin conexion Empty state global + toast "Estas sin internet. Los datos que ves pueden estar desactualizados."
Composicion de errores
Ejemplo compuesto
Submit de formulario con multiples errores.
El usuario pulsa "Confirmar pedido" con 3 campos invalidos y el servidor tambien rechaza por stock insuficiente.
Paso 1: Scroll al primer campo con error + inline errors en los 3 campos
Paso 2: El usuario corrige y reenvía
Paso 3: Servidor responde 400 "Stock insuficiente para Ribeye Limousin"
Paso 4: Toast error con el mensaje del servidor + boton vuelve a activo
Prohibido: Nunca mostrar inline + toast + modal al mismo tiempo. Maximo 2 niveles simultaneos.
Reglas
— SI

Todo error sugiere una accion: "Intenta de nuevo", "Revisa los datos", "Contacta al administrador", "Ir al inicio". Nunca solo describir el problema.

— SI

Errores inline validan en onBlur. Los errores del servidor se muestran como toast. Errores fatales (500, offline) reemplazan el contenido.

— NO

Nunca mostrar codigos HTTP al usuario. "Error 500" no comunica nada. Usar el copy canonico de la tabla de arriba.

— NO

Nunca usar alert() nativo del navegador. Todo error pasa por el sistema de toast o inline validation del design system.

03 — Formularios

Form validation.

Validar en onBlur, no en tiempo real. El usuario merece terminar de escribir antes de que le digamos que esta mal. Errores del servidor se manejan aparte.

Timing
onBlur (campo individual)

Cuando el usuario sale del campo. Aplica para: email, RFC, telefono, campos con formato especifico. El error aparece inline debajo del campo.

onSubmit (formulario completo)

Cuando el usuario pulsa el boton principal. Aplica para: campos requeridos vacios, validaciones cruzadas ("la fecha de entrega no puede ser anterior a hoy"). Scroll al primer error.

Nunca en onChange

No validar mientras el usuario escribe. Un campo de email mostraria error desde la primera letra. Excepcion unica: contador de caracteres (textarea).

Limpiar al corregir

El error inline desaparece tan pronto el campo vuelve a ser valido (en onChange, solo para limpiar, no para validar). El usuario sabe que corrigio bien.

Copy de errores tipo
Tipo de error Copy canonico Notas
Campo vacio "Este campo es obligatorio." Nunca "Required" ni "Campo requerido".
Email invalido "Ingresa un email valido." No mostrar regex ni formato esperado.
RFC invalido "El RFC debe tener 12 o 13 caracteres." Especifico de Mexico. Sin guiones.
Telefono invalido "Ingresa un telefono de 10 digitos." Formato: 222 123 4567 (ver glosario).
Contrasena debil "La contrasena debe tener al menos 8 caracteres." No pedir mayusculas + numeros + simbolos juntos. Solo longitud.
Fuera de rango "El peso debe ser entre 0.1 y 999.9 kg." Incluir los limites exactos.
Formato de fecha "Usa el formato dd/mm/yyyy." Formato mexicano, no americano.
Duplicado "Ya existe un cliente con este RFC." Error del servidor. Se muestra como inline si es un campo, o toast si es general.
Fecha pasada "La fecha de entrega no puede ser anterior a hoy." Validacion cruzada. onSubmit.
Reglas
— SI

Siempre texto + icono para el error. Nunca solo color rojo — WCAG requiere que el error sea comprensible sin color (daltonismo).

— SI

Scroll automatico al primer campo con error en onSubmit. Focus en ese campo. El usuario no tiene que buscarlo.

— NO

Nunca deshabilitar el boton de submit por campos invalidos. El usuario no sabe por que esta deshabilitado. Dejar que pulse y mostrar los errores.

— NO

Nunca "Error en el formulario" generico. Cada campo con error tiene su propio mensaje especifico debajo.

04 — Formularios

Confirmaciones.

No toda accion necesita confirmacion. Solo las destructivas o irreversibles. El exceso de modales de confirmacion entrena al usuario a pulsar "aceptar" sin leer.

Arbol de decision
¿La accion es destructiva o irreversible?
Si → Modal destructivo (rojo) No → Siguiente pregunta
¿La accion tiene consecuencias financieras?
Si → Modal neutro con resumen No → Siguiente pregunta
¿La accion es reversible facilmente?
Si → Ejecutar + toast con "Deshacer" Ejemplo: archivar pedido, quitar de favoritos
¿Es una accion trivial y cotidiana?
Si → Ejecutar sin confirmacion Ejemplo: guardar cambios, agregar al carrito
Escenarios DSPC
Destructivo
Eliminar pedido.
Componente: Modal destructivo
Titulo: "Eliminar pedido PED-08431"
Copy: "Esta accion no se puede deshacer. Se eliminara el pedido y todos sus datos asociados."
Boton primario: "Eliminar pedido" (rojo, --signal)
Boton secundario: "Cancelar"
Post-accion: Toast success "Pedido eliminado" + redirigir a lista
Financiero
Confirmar pedido ($8,240.00).
Componente: Modal neutro con resumen
Titulo: "Confirmar pedido"
Copy: Resumen: 14 cortes · 32.6 kg · Hotel Camino Real · Entrega hoy 14:00–17:00
Total destacado: $ 8,240.00 MXN
Boton primario: "Confirmar pedido" (negro, --ink)
Post-accion: Boton → "Confirmando..." → Toast success
Reversible
Cerrar sesion.
Componente: Ninguno — ejecutar directamente
Post-accion: Redirigir a login + toast info "Sesion cerrada"
Razon: Cerrar sesion es reversible (volver a iniciar). No necesita modal.