{% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {# aria-live on the wrapper, not role="alert" on each message. On a full page load the messages are already in the DOM when the region is created, so role="alert" announced nothing; a live region on a container that is present from the start announces what lands in it, which is what an Unpoly fragment swap does. `assertive` only for errors — a success confirmation should not interrupt what the reader is doing. #}
{% for category, message in messages %} {% set alert_type = 'info' %} {% set alert_icon = 'notifications' %} {% if category == 'error' or category == 'danger' %} {% set alert_type = 'danger' %}{% set alert_icon = 'cancel' %} {% elif category == 'warning' %} {% set alert_type = 'warning' %}{% set alert_icon = 'notifications' %} {% elif category == 'success' %} {% set alert_type = 'success' %}{% set alert_icon = 'check' %} {% endif %}
{# The category was conveyed by hue alone; the icon plus its visually-hidden name carries it without relying on colour. #} {{ icon(alert_icon, label=construct.t("alert-" ~ alert_type)) }} {{ t(message) }} {# Dismissal is the reader's choice. There used to be no control at all, and `data-auto-dismiss` destroyed the message on the next unrelated fragment insertion — possibly before it had been read. #}
{% endfor %}
{% endif %} {% endwith %}