diff --git a/question/type/essay/lang/en/qtype_essay.php b/question/type/essay/lang/en/qtype_essay.php
index f4fd7f3ae29..401516431da 100644
--- a/question/type/essay/lang/en/qtype_essay.php
+++ b/question/type/essay/lang/en/qtype_essay.php
@@ -26,6 +26,8 @@
 $string['acceptedfiletypes'] = 'Accepted file types';
 $string['acceptedfiletypes_help'] = 'Accepted file types can be restricted by entering a list of file extensions. If the field is left empty, then all file types are allowed.';
 $string['allowattachments'] = 'Allow attachments';
+$string['answerfiles'] = 'Answer files';
+$string['answertext'] = 'Answer text';
 $string['attachedfiles'] = 'Attachments: {$a}';
 $string['attachmentsoptional'] = 'Attachments are optional';
 $string['attachmentsrequired'] = 'Require attachments';
diff --git a/question/type/essay/renderer.php b/question/type/essay/renderer.php
index bdb900e81f5..1a78d9ce94e 100644
--- a/question/type/essay/renderer.php
+++ b/question/type/essay/renderer.php
@@ -107,7 +107,7 @@ class qtype_essay_renderer extends qtype_renderer {
     public function files_read_only(question_attempt $qa, question_display_options $options) {
         global $CFG;
         $files = $qa->get_last_qt_files('attachments', $options->context->id);
-        $output = array();
+        $filelist = [];
 
         $step = $qa->get_last_step_with_qt_var('attachments');
 
@@ -126,9 +126,17 @@ class qtype_essay_renderer extends qtype_renderer {
                     'userid' => $step->get_user_id(),
                     'file' => $file]);
             }
-            $output[] = html_writer::tag('p', $out);
+            $filelist[] = html_writer::tag('li', $out, ['class' => 'mb-2']);
         }
-        return implode($output);
+
+        $labelbyid = $qa->get_qt_field_name('attachments') . '_label';
+
+        $output = html_writer::tag('h4', get_string('answerfiles', 'qtype_essay'), ['id' => $labelbyid, 'class' => 'sr-only']);
+        $output .= html_writer::tag('ul', implode($filelist), [
+            'aria-labelledby' => $labelbyid,
+            'class' => 'list-unstyled m-0',
+        ]);
+        return $output;
     }
 
     /**
@@ -172,9 +180,19 @@ class qtype_essay_renderer extends qtype_renderer {
             $filetypedescriptions = $filetypesutil->describe_file_types($filetypes);
             $text .= $this->render_from_template('core_form/filetypes-descriptions', $filetypedescriptions);
         }
-        return $filesrenderer->render($fm). html_writer::empty_tag(
-                'input', array('type' => 'hidden', 'name' => $qa->get_qt_field_name('attachments'),
-                'value' => $pickeroptions->itemid)) . $text;
+
+        $output = html_writer::start_tag('fieldset');
+        $output .= html_writer::tag('legend', get_string('answerfiles', 'qtype_essay'), ['class' => 'sr-only']);
+        $output .= $filesrenderer->render($fm);
+        $output .= html_writer::empty_tag('input', [
+            'type' => 'hidden',
+            'name' => $qa->get_qt_field_name('attachments'),
+            'value' => $pickeroptions->itemid,
+        ]);
+        $output .= $text;
+        $output .= html_writer::end_tag('fieldset');
+
+        return $output;
     }
 
     public function manual_comment(question_attempt $qa, question_display_options $options) {
@@ -264,11 +282,20 @@ class qtype_essay_format_editor_renderer extends plugin_renderer_base {
     }
 
     public function response_area_read_only($name, $qa, $step, $lines, $context) {
-        return html_writer::tag('div', $this->prepare_response($name, $qa, $step, $context),
-                ['class' => $this->class_name() . ' qtype_essay_response readonly',
-                        'style' => 'min-height: ' . ($lines * 1.5) . 'em;']);
+        $labelbyid = $qa->get_qt_field_name($name) . '_label';
+
+        $output = html_writer::tag('h4', get_string('answertext', 'qtype_essay'), ['id' => $labelbyid, 'class' => 'sr-only']);
+        $output .= html_writer::tag('div', $this->prepare_response($name, $qa, $step, $context), [
+            'role' => 'textbox',
+            'aria-readonly' => 'true',
+            'aria-labelledby' => $labelbyid,
+            'class' => $this->class_name() . ' qtype_essay_response readonly',
+            'style' => 'min-height: ' . ($lines * 1.5) . 'em;',
+        ]);
         // Height $lines * 1.5 because that is a typical line-height on web pages.
         // That seems to give results that look OK.
+
+        return $output;
     }
 
     public function response_area_input($name, $qa, $step, $lines, $context) {
@@ -293,7 +320,10 @@ class qtype_essay_format_editor_renderer extends plugin_renderer_base {
         $editor->use_editor($id, $this->get_editor_options($context),
                 $this->get_filepicker_options($context, $draftitemid));
 
-        $output = '';
+        $output = html_writer::tag('label', get_string('answertext', 'qtype_essay'), [
+            'class' => 'sr-only',
+            'for' => $id,
+        ]);
         $output .= html_writer::start_tag('div', array('class' =>
                 $this->class_name() . ' qtype_essay_response'));
 
@@ -500,14 +530,22 @@ class qtype_essay_format_plain_renderer extends plugin_renderer_base {
     }
 
     public function response_area_read_only($name, $qa, $step, $lines, $context) {
-        return $this->textarea($step->get_qt_var($name), $lines, array('readonly' => 'readonly'));
+        $id = $qa->get_qt_field_name($name) . '_id';
+
+        $output = html_writer::tag('label', get_string('answertext', 'qtype_essay'), ['class' => 'sr-only', 'for' => $id]);
+        $output .= $this->textarea($step->get_qt_var($name), $lines, ['id' => $id, 'readonly' => 'readonly']);
+        return $output;
     }
 
     public function response_area_input($name, $qa, $step, $lines, $context) {
         $inputname = $qa->get_qt_field_name($name);
-        return $this->textarea($step->get_qt_var($name), $lines, array('name' => $inputname)) .
-                html_writer::empty_tag('input', array('type' => 'hidden',
-                    'name' => $inputname . 'format', 'value' => FORMAT_PLAIN));
+        $id = $inputname . '_id';
+
+        $output = html_writer::tag('label', get_string('answertext', 'qtype_essay'), ['class' => 'sr-only', 'for' => $id]);
+        $output .= $this->textarea($step->get_qt_var($name), $lines, ['name' => $inputname, 'id' => $id]);
+        $output .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => $inputname . 'format', 'value' => FORMAT_PLAIN]);
+
+        return $output;
     }
 }