diff --git a/Tests/LibWeb/Text/expected/textarea-selection-start-selection-end.txt b/Tests/LibWeb/Text/expected/textarea-selection-start-selection-end.txt
new file mode 100644
index 00000000000..4ad111b5fa7
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/textarea-selection-start-selection-end.txt
@@ -0,0 +1,4 @@
+Well hello friends selectionStart: 0
+selectionEnd: 0
+selectionStart: 18
+selectionEnd: 18
diff --git a/Tests/LibWeb/Text/input/textarea-selection-start-selection-end.html b/Tests/LibWeb/Text/input/textarea-selection-start-selection-end.html
new file mode 100644
index 00000000000..00aadd9015f
--- /dev/null
+++ b/Tests/LibWeb/Text/input/textarea-selection-start-selection-end.html
@@ -0,0 +1,15 @@
+
+
+
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp
index fc15d6cee38..c49bb17f064 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp
@@ -201,6 +201,63 @@ void HTMLTextAreaElement::set_custom_validity(String const& error)
dbgln("(STUBBED) HTMLTextAreaElement::set_custom_validity(\"{}\"). Called on: {}", error, debug_description());
}
+// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectionstart
+WebIDL::UnsignedLong HTMLTextAreaElement::selection_start() const
+{
+ // 1. If this element is an input element, and selectionStart does not apply to this element, return null.
+
+ // 2. If there is no selection, return the code unit offset within the relevant value to the character that
+ // immediately follows the text entry cursor.
+ if (auto const* browsing_context = document().browsing_context()) {
+ if (auto cursor = browsing_context->cursor_position())
+ return cursor->offset();
+ }
+
+ // FIXME: 3. Return the code unit offset within the relevant value to the character that immediately follows the start of
+ // the selection.
+ return 0;
+}
+
+// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#textFieldSelection:dom-textarea/input-selectionstart-2
+WebIDL::ExceptionOr HTMLTextAreaElement::set_selection_start(WebIDL::UnsignedLong)
+{
+ // 1. If this element is an input element, and selectionStart does not apply to this element, throw an
+ // "InvalidStateError" DOMException.
+
+ // FIXME: 2. Let end be the value of this element's selectionEnd attribute.
+ // FIXME: 3. If end is less than the given value, set end to the given value.
+ // FIXME: 4. Set the selection range with the given value, end, and the value of this element's selectionDirection attribute.
+ return {};
+}
+
+// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectionend
+WebIDL::UnsignedLong HTMLTextAreaElement::selection_end() const
+{
+ // 1. If this element is an input element, and selectionEnd does not apply to this element, return null.
+
+ // 2. If there is no selection, return the code unit offset within the relevant value to the character that
+ // immediately follows the text entry cursor.
+ if (auto const* browsing_context = document().browsing_context()) {
+ if (auto cursor = browsing_context->cursor_position())
+ return cursor->offset();
+ }
+
+ // FIXME: 3. Return the code unit offset within the relevant value to the character that immediately follows the end of
+ // the selection.
+ return 0;
+}
+
+// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#textFieldSelection:dom-textarea/input-selectionend-3
+WebIDL::ExceptionOr HTMLTextAreaElement::set_selection_end(WebIDL::UnsignedLong)
+{
+ // 1. If this element is an input element, and selectionEnd does not apply to this element, throw an
+ // "InvalidStateError" DOMException.
+
+ // FIXME: 2. Set the selection range with the value of this element's selectionStart attribute, the given value, and the
+ // value of this element's selectionDirection attribute.
+ return {};
+}
+
// https://html.spec.whatwg.org/multipage/form-elements.html#dom-textarea-maxlength
WebIDL::Long HTMLTextAreaElement::max_length() const
{
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h
index 7f254cec57d..44d8be94372 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h
@@ -84,6 +84,12 @@ public:
bool report_validity();
void set_custom_validity(String const& error);
+ WebIDL::UnsignedLong selection_start() const;
+ WebIDL::ExceptionOr set_selection_start(WebIDL::UnsignedLong);
+
+ WebIDL::UnsignedLong selection_end() const;
+ WebIDL::ExceptionOr set_selection_end(WebIDL::UnsignedLong);
+
WebIDL::Long max_length() const;
WebIDL::ExceptionOr set_max_length(WebIDL::Long);
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.idl
index 5e7349437ab..52a2276f71f 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.idl
+++ b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.idl
@@ -35,8 +35,8 @@ interface HTMLTextAreaElement : HTMLElement {
// FIXME: readonly attribute NodeList labels;
// FIXME: undefined select();
- // FIXME: attribute unsigned long selectionStart;
- // FIXME: attribute unsigned long selectionEnd;
+ attribute unsigned long selectionStart;
+ attribute unsigned long selectionEnd;
// FIXME: attribute DOMString selectionDirection;
// FIXME: undefined setRangeText(DOMString replacement);
// FIXME: undefined setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode = "preserve");