From be51e4bf8ceaf14bbc5977892a9ac74afefb54c0 Mon Sep 17 00:00:00 2001
From: Fons van der Plas <fonsvdplas@gmail.com>
Date: Thu, 4 Jan 2024 00:10:25 +0100
Subject: [PATCH] =?UTF-8?q?=F0=9F=97=A3=EF=B8=8F=20Screen=20reader=20suppo?=
 =?UTF-8?q?rt=20for=20reactive=20output=20changes=20(#2757)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 frontend/components/CellOutput.js | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/frontend/components/CellOutput.js b/frontend/components/CellOutput.js
index a58979b88e..b2a6244b88 100644
--- a/frontend/components/CellOutput.js
+++ b/frontend/components/CellOutput.js
@@ -34,7 +34,9 @@ const prettyAssignee = (assignee) =>
 export class CellOutput extends Component {
     constructor() {
         super()
-        this.state = {}
+        this.state = {
+            output_changed_once: false,
+        }
 
         this.old_height = 0
         // @ts-ignore Is there a way to use the latest DOM spec?
@@ -60,6 +62,12 @@ export class CellOutput extends Component {
         return last_run_timestamp !== this.props.last_run_timestamp || sanitize_html !== this.props.sanitize_html
     }
 
+    componentDidUpdate(old_props) {
+        if (this.props.last_run_timestamp !== old_props.last_run_timestamp) {
+            this.setState({ output_changed_once: true })
+        }
+    }
+
     componentDidMount() {
         this.resize_observer.observe(this.base)
     }
@@ -84,8 +92,12 @@ export class CellOutput extends Component {
                 })}
                 translate=${allow_translate}
                 mime=${this.props.mime}
+                aria-live=${this.state.output_changed_once ? "polite" : "off"}
+                aria-atomic="true"
+                aria-relevant="all"
+                aria-label=${this.props.rootassignee == null ? "Result of unlabeled cell:" : `Result of variable ${this.props.rootassignee}:`}
             >
-                <assignee translate=${false}>${prettyAssignee(this.props.rootassignee)}</assignee>
+                <assignee aria-hidden="true" translate=${false}>${prettyAssignee(this.props.rootassignee)}</assignee>
                 <${OutputBody} ...${this.props} />
             </pluto-output>
         `