# `Excessibility.LiveViewRules.Rules.RevealWithoutAnnouncement`
[🔗](https://github.com/lessthanseventy/excessibility/blob/v0.18.1/lib/excessibility/live_view_rules/rules/reveal_without_announcement.ex#L1)

Flags initially hidden containers that are revealed from the server
without exposing that reveal to assistive technology.

A common LiveView pattern un-hides a container without any page
navigation or focus change — e.g. `push_event(socket, "js-exec", %{to:
"#cap-reached-banner", attr: "data-show"})` executing a `JS.show`
command stored on the element, or a sibling `phx-click={JS.show(to:
"#banner")}`. Visually the banner appears; for a screen-reader user
nothing happens, because at rest the element is hidden and carries no
`role="alert"` / `role="status"` / `aria-live`. axe-core cannot catch
this — the element is hidden when it scans.

## What's flagged

An element for which **all** of the following hold:

  1. It is initially hidden — a `hidden` class, inline `display:none`,
     or the `hidden` attribute.
  2. It is a reveal target, detectable statically as either a `data-*`
     attribute on the element whose value is a serialized
     `JS.show`/`JS.toggle` command (the `js-exec` idiom), or another
     element's `phx-*` attribute carrying a `show`/`toggle` op whose
     `to` targets this element's id.
  3. It exposes no announcement — no `role="alert"`, `role="status"`,
     `role="log"`, no `aria-live`, and no ancestor providing one.

Reveal targets that are dialogs (`role="dialog"` / `aria-modal`) are
skipped: dialogs have their own correct focus-management pattern.

## Fix

    <!-- Bad -->
    <div id="banner" class="hidden" data-show={JS.show(display: "flex")}>
      You've reached your cap.
    </div>

    <!-- Good: informational transition -->
    <div id="banner" class="hidden" role="status" data-show={JS.show(display: "flex")}>
      You've reached your cap.
    </div>

---

*Consult [api-reference.md](api-reference.md) for complete listing*
