Si programas para Android o trabajas con interfaces web, antes o después te tocará mostrar un cuadro emergente que pida confirmación, avise de un error o solicite más datos. Es decir, vas a necesitar interactuar con tus usuarios mediante diálogos que capten su atención de forma clara y accesible. Un buen uso de estos componentes marca la diferencia entre una app tosca y una que se siente pulida y profesional.
En este artículo vas a ver, paso a paso, cómo programar un AlertDialog desde cero en Android, cómo crear diálogos basados en tarjetas en Google Chat, y qué exige la accesibilidad web cuando se usa el rol ARIA alertdialog. Integraremos todo este conocimiento, lo explicaremos con un lenguaje cercano, y lo organizaremos en secciones para que puedas adaptar cada enfoque a tu proyecto, ya sea una app nativa, una app de chat o una interfaz web accesible.
¿Qué es un diálogo y cuándo usarlo?
Un diálogo es, en esencia, una ventana flotante que reclama la atención del usuario para que tome una decisión o aporte información adicional. No ocupa la pantalla completa, se superpone sobre la interfaz actual y, en la mayoría de los casos, se comporta como un elemento modal: hasta que el usuario no interactúa con él, no puede continuar usando el resto de la UI.
En Android y en otras plataformas se recomienda seguir unas guías de diseño específicas para diálogos, como las de Material Design, donde se detalla cómo estructurar el contenido, el texto de los botones, la jerarquía visual y la adaptación a distintos idiomas. Respetar estas pautas hace que tus diálogos sean más coherentes con el sistema y más fáciles de entender para el usuario.
Clases de diálogos en Android: la base de AlertDialog
En Android, la clase fundamental es Dialog, que actúa como clase base para casi todos los cuadros de diálogo. Sin embargo, la propia plataforma desaconseja crear instancias directas de Dialog; en su lugar se deben usar subclases diseñadas para casos de uso concretos.
Las subclases más habituales que necesitas conocer son AlertDialog, DatePickerDialog y TimePickerDialog. Cada una viene con una interfaz predefinida optimizada para un propósito: mostrar avisos y opciones, elegir una fecha o seleccionar una hora, respectivamente.
Durante años también se utilizó ProgressDialog para mostrar barras de progreso, pero esta clase está obsoleta. Bloquea la interacción con la app mientras muestra el avance, lo que va en contra de las recomendaciones modernas de usabilidad. Si necesitas indicar carga o progreso indeterminado, lo apropiado hoy es seguir las guías de Material sobre progreso y actividad y usar un ProgressBar integrado en tu diseño, en lugar de recurrir a un diálogo modal que paralice la aplicación.
¿Por qué usar DialogFragment para gestionar tus diálogos?
Además de la clase de diálogo en sí, Android recomienda que la ventana esté envuelta en un DialogFragment, que actúa como contenedor. Esta clase se encarga de gestionar el ciclo de vida del diálogo, su restauración tras giros de pantalla y el manejo del botón Atrás, entre otros aspectos.
Al crear un DialogFragment que devuelve un AlertDialog en onCreateDialog(), delegas en el framework todo el control sobre recreaciones, cambios de configuración y posibles fugas de memoria que aparecerían si gestionaras el Dialog a mano. Además, puedes reutilizar la interfaz del diálogo como parte de una pantalla más grande, integrándola igual que harías con cualquier otro Fragment.
Esta flexibilidad resulta muy útil cuando quieres que el mismo contenido se muestre como ventana emergente en móviles y como panel integrado en pantallas grandes. Con DialogFragment puedes decidir en tiempo de ejecución si lo presentas como cuadro de diálogo o como un fragmento que ocupe parte o toda la pantalla.
Crear un DialogFragment que use AlertDialog
Para construir un diálogo de alerta clásico en Android, el patrón típico consiste en extender DialogFragment y sobrescribir onCreateDialog(). Dentro de ese método, se utiliza un AlertDialog.Builder para configurar título, mensaje, vista personalizada, listas y botones.
En un ejemplo básico, crearías una instancia de AlertDialog.Builder con el contexto de la actividad, definirías el contenido con los métodos setTitle(), setMessage() o setView(), configurarías botones con setPositiveButton() y compañía, y por último llamarías a create() para obtener el AlertDialog final. El DialogFragment se encarga luego de mostrarlo al invocar show() sobre una instancia suya, usando el FragmentManager correspondiente.
Este enfoque se puede combinar con otros métodos de ciclo de vida estándar de Fragment (como onCreate(), onStart(), onDestroyView(), etc.), lo que te permite inicializar datos, limpiar recursos o reaccionar a cambios de orientación de manera ordenada.
Estructura de un AlertDialog: título, contenido y botones
Un AlertDialog estándar se divide, visualmente, en tres regiones principales bien diferenciadas: la zona de título, el área de contenido y la fila de botones de acción en la parte inferior.
El título es totalmente opcional; suele utilizarse cuando el contenido está ocupado por un mensaje largo, una lista de elementos o un diseño personalizado. Si el mensaje que quieres mostrar es breve y directo (por ejemplo, una pregunta de sí o no), es habitual omitir el título para simplificar.
La zona de contenido permite presentar un mensaje de texto, una lista de ítems o un diseño arbitrario definido mediante un layout XML. La API de AlertDialog.Builder incluye métodos para cada caso: setMessage(), setItems(), setSingleChoiceItems(), setMultiChoiceItems() o setView() cuando quieres inflar un layout propio.
En la franja inferior se sitúan hasta tres botones de acción: positivo, negativo y neutral. Cada uno se asocia a un DialogInterface.OnClickListener que recibe el evento cuando el usuario lo pulsa. El sistema se encarga de ordenar y dar estilo coherente a estos botones según las guías de Android.
Configurar botones de acción en un AlertDialog

Los botones se agregan a través de los métodos setPositiveButton(), setNegativeButton() y setNeutralButton(). Todos reciben como parámetros el texto del botón (normalmente salido de recursos de cadenas) y un listener que define la lógica a ejecutar al pulsarse.
El botón positivo representa la acción de aceptar y continuar (por ejemplo, confirmar un borrado, guardar cambios o enviar información). El negativo se reserva para cancelar la operación, restaurar el estado anterior o simplemente cerrar el diálogo sin aplicar cambios.
El botón neutral se usa cuando el usuario no quiere seguir adelante, pero tampoco desea cancelar del todo. Suele emplearse para opciones intermedias como “Recordar más tarde”, “Omitir ahora” o “Más información”. En el orden visual, aparece entre el positivo y el negativo.
Es importante tener claro que solo puede haber un botón de cada tipo. No es posible configurar dos botones positivos distintos en el mismo AlertDialog; si necesitas más acciones, deberías plantear un diseño distinto, como una lista de opciones.
Crear listas en un AlertDialog
Las APIs de AlertDialog permiten mostrar distintos tipos de listas en el área de contenido. Esto resulta ideal cuando quieres que el usuario elija entre varias opciones dentro del propio diálogo, sin mostrar una pantalla adicional.
Existen tres variantes principales: la lista de opción única tradicional, donde al pulsar un elemento se cierra el diálogo y se devuelve ese valor; la lista de opción única persistente basada en radio buttons, donde se mantiene la selección visible; y la lista de opciones múltiples persistente con casillas de verificación, útil para configuraciones con varias opciones simultáneas.
Para una lista simple de opción única, se utiliza setItems() pasando un array de cadenas definido como recurso o construido en código. El listener asociado recibe el índice del ítem pulsado, y, por defecto, al seleccionar uno se cierra el diálogo. Como el área de contenido se ocupa por la lista, no se puede mostrar al mismo tiempo un mensaje de texto independiente; si necesitas un encabezado, lo proporcionas mediante setTitle().
Si en lugar de un array fijo quieres respaldar la lista con datos dinámicos obtenidos de una base de datos o de la red, puedes recurrir a setAdapter(). Este enfoque te permite usar un ListAdapter completo y, siguiendo las buenas prácticas, cargar el contenido de forma asíncrona mediante un Loader u otros mecanismos modernos como ViewModel y LiveData.
Listas persistentes de opción única y múltiples opciones
Cuando la selección debe quedar visible mientras el diálogo está abierto (por ejemplo, en un panel de ajustes), se recurre a setSingleChoiceItems() para opción única y a setMultiChoiceItems() para selección múltiple con casillas. Ambos métodos aceptan arrays de texto o adaptadores, y permiten controlar qué elementos están marcados inicialmente.
En un caso típico de multiselección, sueles mantener una estructura de datos en memoria (como una ArrayList<Integer> o un array de booleanos) donde vas guardando los índices de los ítems seleccionados o un estado marcado/no marcado por posición. Cada vez que el usuario marca o desmarca una casilla, el listener se dispara y puedes actualizar esa colección.
Para un cuadro de diálogo de opción única con radio buttons, el patrón es similar, pero solo un elemento puede estar activo a la vez. Al pulsar una opción, actualizas la variable que representa la elección seleccionada. El diálogo puede tener además botones de positiva/negativa para confirmar o cancelar la selección realizada.
Construir un AlertDialog con un diseño personalizado
Cuando el diseño estándar de título, mensaje y botones se queda corto, Android permite inflar un layout XML personalizado dentro del diálogo usando el método setView() de AlertDialog.Builder. De esta forma puedes incluir imágenes, campos de texto, controles compuestos, pestañas y cualquier otro widget.
Un ejemplo típico es un diálogo de inicio de sesión con ImageView y dos EditText. El archivo de diseño podría definirse en res/layout/dialog_signin.xml con un LinearLayout vertical que contenga un logo y los campos de usuario y contraseña. Cada EditText establecería su inputType apropiado: correo electrónico para el usuario y textPassword para la clave.
Hay pequeños detalles de usabilidad que conviene cuidar, como el hecho de que, al usar inputType="textPassword", la fuente por defecto pase a monoespaciada. Para mantener una apariencia homogénea con el resto del diseño, puedes forzar la familia tipográfica a sans-serif en el XML del campo de contraseña.
En el DialogFragment, obtienes un LayoutInflater llamando a getLayoutInflater() y luego inflas el recurso con inflate(), pasando como primer parámetro el ID del layout y como segundo una vista padre opcional (que normalmente será null en este contexto). El resultado es una vista que se asigna al cuadro de diálogo con setView(), a partir de la cual puedes obtener referencias a los controles, validar inputs y reaccionar a los botones.
Mostrar una Activity como diálogo
Si necesitas una interfaz muy compleja o reutilizar una layout completa, puede interesarte mostrar una Activity con apariencia de cuadro de diálogo. En lugar de recurrir a Dialog, defines una actividad normal y le asignas un tema de estilo diálogo en el manifiesto, por ejemplo Theme.Holo.Dialog.
Con este enfoque, la nueva pantalla no ocupa necesariamente toda el área visible y puede combinarse con multiventana. La ventaja es que puedes aprovechar todo el ciclo de vida de Activity y estructurar la UI con mayor libertad, algo muy útil en tablets o en flujos de corta duración que conviene destacar sin ocultar por completo el contexto.
Pasar eventos del diálogo a la Activity o Fragment
Aunque tu DialogFragment puede gestionar por sí mismo los eventos de sus botones, es muy habitual que necesites comunicar el resultado a la actividad o fragmento que lo abrió. Para ello, se recomienda definir una interfaz dentro del propio fragmento.
Esa interfaz declara uno o varios métodos de callback (por ejemplo, onDialogPositiveClick() y onDialogNegativeClick()) que describen los posibles resultados. El componente host (actividad o fragmento padre) implementa dicha interfaz, y el DialogFragment obtiene una referencia a esa implementación normalmente en onAttach(), verificando que el contexto la implemente.
Cuando el usuario pulsa un botón o selecciona un ítem relevante, el DialogFragment llama al método correspondiente de la interfaz implementada, de forma que la lógica principal se ejecuta en el host. Esto mantiene el cuadro de diálogo enfocado únicamente a la presentación y validación, dejando el flujo de negocio en el componente que lo invocó.
Mostrar y recuperar un DialogFragment
Para presentar el diálogo en pantalla, creas una instancia de tu DialogFragment y llamas a show(), pasando un FragmentManager y una etiqueta de texto que identifique el fragmento. Si lo llamas desde una FragmentActivity, usarás getSupportFragmentManager(); si lo haces desde otro Fragment, lo común es emplear getParentFragmentManager().
La etiqueta que proporcionas a show() sirve para que el sistema pueda guardar y restaurar el estado del diálogo en determinadas circunstancias y, además, para que tú puedas recuperarlo más adelante llamando a findFragmentByTag(). Esto es útil si quieres consultar su estado o descartarlo manualmente desde otro punto del código.
Diálogo en pantalla completa o fragmento integrado
En algunas interfaces sofisticadas, sobre todo en tablets o pantallas grandes, te interesará que el mismo contenido se comporte a veces como diálogo y otras como fragmento embebido. En este escenario, no puedes basarte en AlertDialog.Builder ni en otras subclases de Dialog, porque necesitas una UI completamente integrable.
La estrategia es definir el diseño en un layout XML que se cargará con onCreateView() en el DialogFragment, en lugar de usar onCreateDialog(). Así, tu fragmento puede mostrarse como un panel integrado en una transacción de fragmentos convencional o como un diálogo dependiendo del tamaño de pantalla o de la lógica de la app.
Para decidir este comportamiento, se suele usar un recurso booleano que indica si el dispositivo tiene un layout grande. Por ejemplo, puedes definir res/values/bools.xml con <bool name="large_layout">false</bool> y otra versión alternativa en res/values-large/bools.xml poniendo ese mismo valor a true. En el onCreate() de la actividad, lees este booleano y lo asignas a una variable como mIsLargeLayout.
A partir de ahí, tu código puede decidir si inicia el fragmento como diálogo modal o como fragmento a pantalla completa. En pantallas compactas quizá prefieras reemplazar el contenido de la actividad, mientras que en pantallas amplias puede resultar más cómodo abrirlo como ventana flotante sobre el layout principal.
Mostrar una Activity como diálogo solo en pantallas grandes
Otra opción interesante para mejorar la experiencia en tablets es mostrar ciertas actividades como diálogos únicamente en dispositivos grandes. Android ofrece temas específicos para esto, como Theme.Holo.DialogWhenLarge, que convierten una actividad normal en una ventana flotante solo cuando el tamaño de pantalla lo permite.
En la práctica, esto te permite diseñar flujos pensados para móviles que, en pantallas grandes, se vean más elegantes al aparecer como diálogos en lugar de ocupar todo el espacio. El usuario percibe un contexto más rico al seguir viendo el contenido de fondo mientras resuelve la tarea puntual del cuadro de diálogo.
Gestionar el cierre y la cancelación de un diálogo
En Android, si el usuario pulsa un botón de acción creado con AlertDialog.Builder o selecciona un elemento de una lista no persistente, el sistema suele cerrar automáticamente el diálogo. No obstante, hay casos en los que necesitas controlar explícitamente el cierre, por ejemplo cuando hay campos que validar.
Para descartar manualmente la ventana, puedes llamar a dismiss() sobre el propio DialogFragment. Si quieres distinguir entre “cerrar normalmente” y “cancelar” (por ejemplo, al pulsar Atrás o tocar fuera del cuadro en un diálogo cancelable), puedes implementar onCancel() y onDismiss() en tu clase.
Es importante saber que cada cancelación dispara también onDismiss(), pero un cierre explícito mediante Dialog.dismiss() o DialogFragment.dismiss() solo invoca onDismiss(), no onCancel(). Normalmente se recurre a dismiss() cuando el usuario ha confirmado con el botón positivo y quieres simplemente retirar el diálogo de la vista tras completar la acción.
Ejemplo práctico: construcción completa de un AlertDialog en Android
Imagina que has creado una aplicación sencilla con un EditText, dos TextView y un Button en un proyecto de Android Studio. El objetivo es que el usuario introduzca su nombre, pulse el botón y se abra un AlertDialog que pida un dato numérico adicional, para luego mostrar un mensaje de confirmación.
En el layout principal colocarías los textos, el campo de entrada y el botón, ajustando atributos como gravity, textAlignment y textSize para centrar y dar formato. Elstrings.xml definirías las cadenas usadas en la interfaz: etiquetas de los TextView, texto del botón, mensajes del diálogo y títulos relevantes.
En la MainActivity, declararías referencias para el EditText, el Button, el TextView final, un AlertDialog.Builder y, si quieres dar feedback rápido, un Toast. Dentro de onCreate() instancias los componentes con findViewById(), configuras el OnClickListener del botón y compruebas si el usuario ha escrito algo en el campo de nombre.
Si la longitud del texto introducido es cero, preparas una cadena de aviso y la muestras mediante un Toast para pedir al usuario que rellene el campo. Si hay contenido, en el bloque else comienzas a construir el AlertDialog.
Creas el AlertDialog.Builder pasando como contexto la propia actividad actual (por ejemplo, this o NombreDeLaActivity.this). Es crucial no usar getApplicationContext() para este tipo de diálogos, porque puede provocar que la ventana no se muestre correctamente o produzca errores.
A continuación defines un LinearLayout que va a contener dos TextView y un EditText numérico. Les asignas contexto de la actividad, configuras el texto de cada etiqueta con setText() usando cadenas de strings.xml, y al EditText le pones tipo de entrada numérico con combinaciones como InputType.TYPE_CLASS_NUMBER e incluso InputType.TYPE_NUMBER_VARIATION_NORMAL si necesitas dígitos enteros.
Para mejorar la legibilidad, puedes ajustar el ancho mínimo con setWidth(100), centrar el texto con setTextAlignment(EditText.TEXT_ALIGNMENT_CENTER) y limitar la longitud máxima usando filtros de tipo LengthFilter para que el usuario solo pueda introducir, por ejemplo, cinco dígitos.
Al layout lineal le cambias la orientación a horizontal con setOrientation(LinearLayout.HORIZONTAL), añades relleno alrededor con setPadding() y centras todo su contenido usando setGravity(Gravity.CENTER). Por último, incorporas los tres elementos con addView() y asignas el layout completo al diálogo mediante builder.setView(linearLayout).
En cuanto a los botones, configuras un botón positivo que, al pulsarse, lea el valor introducido y lo muestre en el TextView de confirmación de la actividad. El botón neutral puede servir para sugerir que el usuario revise sus datos, y el negativo para limpiar el campo numérico y pedirle que lo introduzca de nuevo. Cada uno tendrá su texto procedente de strings.xml y su listener correspondiente.
Cuando terminas la configuración, creas el diálogo con AlertDialog dialog = builder.create() y lo muestras con dialog.show(). Ya tienes un AlertDialog completo que integra validación básica, layout personalizado y comunicación con la actividad principal.
Diálogos interactivos en Google Chat
Más allá de Android, también es posible interactuar con los usuarios mediante diálogos en apps de Google Chat. Aquí los diálogos se presentan como ventanas basadas en tarjetas (card-based UI) que se abren sobre un espacio de Chat o sobre un mensaje concreto, y solo son visibles para la persona que los lanzó.
Las apps de Chat emplean estos diálogos para pedir y recopilar información a través de formularios de uno o varios pasos. Para diseñar formularios, se usan widgets de entrada (campos de texto, listas desplegables, casillas, etc.) definidos dentro de la estructura de la tarjeta. La documentación de Google detalla cómo construir estas entradas y procesar la información que los usuarios envían.
Activar una solicitud de diálogo en Google Chat
Una app de Chat solo puede abrir diálogos en respuesta directa a una interacción del usuario, como un comando slash, el clic en un botón dentro de una tarjeta o una acción desde la página principal de la app.
Para que un comando pueda abrir un diálogo, al configurarlo en la consola debes marcar explícitamente la opción que indica que dicho comando abre un cuadro de diálogo. Si la activación se produce desde un botón en un mensaje de tarjeta, en la definición del botón se establece la acción onClick con su campo interaction configurado a OPEN_DIALOG.
De esta manera, cuando el usuario pulsa el botón, se envía a tu app un evento de interacción de tipo event en la API de Chat, donde el campo dialogEventType pasa a ser REQUEST_DIALOG, indicando que el usuario ha solicitado abrir un diálogo.
Abrir el diálogo inicial y manejar envíos
Cuando recibes este evento con REQUEST_DIALOG, tu servicio debe responder devolviendo un objeto actionResponse con type igual a DIALOG, acompañado de los datos del mensaje que describe el contenido del cuadro de diálogo.
El contenido lo define un objeto dialogAction cuyo campo body contiene las secciones, widgets y elementos de la interfaz que se mostrarán en la ventana emergente. En esa estructura puedes añadir campos de formulario, botones de envío y cualquier otro componente permitido por la API de tarjetas.
Al pulsar un botón que envía el formulario, tu app recibe un evento de interacción de tipo CARD_CLICKED con dialogEventType igual a SUBMIT_DIALOG. La información introducida por el usuario llega dentro de event.common.formInputs, que deberás procesar para validar datos, guardar en base de datos o desencadenar otras acciones.
Tu app puede responder a este evento de envío cerrando el diálogo o devolviendo otro cuadro de diálogo encadenado. Esta segunda opción es especialmente útil para flujos de varios pasos, revisiones intermedias o cuando quieres completar contenidos del formulario de forma dinámica en función de lo que la persona haya escrito previamente.
Si necesitas arrastrar datos de un diálogo a otro, puedes incluir parámetros adicionales en el botón que abre el siguiente cuadro. Esa información se pasa como parte de la acción y te permite ir construyendo un contexto compartido entre todos los pasos del formulario.
Cerrar el diálogo y mostrar notificaciones en Google Chat
Cuando se completa la acción asociada a un botón de diálogo, tu app de Chat debe devolver un ActionResponse con type establecido en DIALOG y un dialogAction adecuadamente configurado. Si todo ha salido bien, el campo actionStatus suele ponerse en OK, lo que indica a la interfaz de Chat que puede cerrar el cuadro sin mensajes de error.
Opcionalmente, tienes la posibilidad de mostrar una notificación de texto temporal al usuario que ha interactuado. Esto se consigue devolviendo un ActionResponse con un actionStatus que incluya el texto de confirmación o de error. Es una forma rápida de indicar si los parámetros eran válidos, si se ha guardado la información o si falta algo por completar.
Además, al cerrar el diálogo, tu app puede enviar un nuevo mensaje de chat o actualizar uno existente. Para mandar uno nuevo, se devuelve un ActionResponse cuyo type sea NEW_MESSAGE junto con el contenido del mensaje de confirmación. Para actualizar mensajes ya publicados, se usan otros tipos de respuesta, siempre incluyendo el mensaje modificado.
En caso de errores o comportamientos inesperados, es posible que la interfaz de Chat muestre un mensaje genérico tipo “Se produjo un error” o directamente no muestre nada. Para depurar, Google Chat ofrece mensajes de error más detallados y datos de registro siempre que tengas activado el log de errores para tu app. La documentación de solución de problemas explica cómo consultarlos y corregir los fallos típicos (parámetros incorrectos, formatos inválidos o permisos insuficientes).
Accesibilidad web: uso correcto del rol ARIA alertdialog
En el mundo web, cuando construyes un diálogo accesible con ARIA es clave entender la diferencia entre dialog y alertdialog. Ambos roles representan cajas de diálogo, pero el segundo se reserva para situaciones urgentes que requieren atención inmediata, como errores graves o advertencias críticas.
Un cuadro con rol alertdialog debe contar siempre con un nombre accesible, proporcionado mediante aria-labelledby o aria-label. Además, el texto de alerta debe indicarse como descripción accesible usando aria-describedby, de forma que los lectores de pantalla puedan anunciar claramente el propósito y el contenido del mensaje al usuario.
A diferencia de un simple rol alert, que solo anuncia un mensaje, un alertdialog debe incluir al menos un control enfocable, normalmente un botón de Confirmar, Cerrar o Cancelar. Cuando el diálogo aparece, el foco se traslada a ese control inicial, permitiendo que las personas que navegan con teclado o tecnología asistida puedan interactuar sin perderse.
Estos diálogos pueden contener otros elementos interactivos, como campos de texto, pestañas o casillas de verificación. El control al que se dirige el foco por defecto depende del propósito del diálogo: en algunos casos será el botón principal, en otros un campo que el usuario debe rellenar de inmediato.
El orden de tabulación dentro del alertdialog debe estar bien definido, de modo que el foco se circule correctamente por todos los controles del cuadro sin escapar a la página que hay detrás mientras el diálogo esté activo. Al ser componentes modales por naturaleza, el foco no debería salir del diálogo hasta que se cierre.
La recomendación es reservar el rol alertdialog para alertas, errores o advertencias urgentes. Cuando la información es de naturaleza más neutra, o las acciones no requieren atención inmediata, es preferible usar simplemente el rol dialog estándar. Depende del desarrollador hacer esta distinción en función de la criticidad del mensaje y de la experiencia que quiera ofrecer.
Con todo lo anterior, dispones de una panorámica bastante completa de cómo interactuar con tus usuarios mediante diálogos en Android, Google Chat y la web accesible. Entender las clases nativas, los patrones de integración, los flujos de eventos y los requisitos de accesibilidad te permite construir cuadros de diálogo robustos, claros y respetuosos con las necesidades de todo tipo de usuarios. Comparte la información para que más usuarios conozcan del tema.

