diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
index ac514b3730..497db27f09 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
@@ -379,6 +379,38 @@ void HTMLInputElement::update_placeholder_visibility()
}
}
+// https://html.spec.whatwg.org/multipage/input.html#the-input-element:attr-input-readonly-3
+static bool is_allowed_to_be_readonly(HTML::HTMLInputElement::TypeAttributeState state)
+{
+ switch (state) {
+ case HTML::HTMLInputElement::TypeAttributeState::Text:
+ case HTML::HTMLInputElement::TypeAttributeState::Search:
+ case HTML::HTMLInputElement::TypeAttributeState::Telephone:
+ case HTML::HTMLInputElement::TypeAttributeState::URL:
+ case HTML::HTMLInputElement::TypeAttributeState::Email:
+ case HTML::HTMLInputElement::TypeAttributeState::Password:
+ case HTML::HTMLInputElement::TypeAttributeState::Date:
+ case HTML::HTMLInputElement::TypeAttributeState::Month:
+ case HTML::HTMLInputElement::TypeAttributeState::Week:
+ case HTML::HTMLInputElement::TypeAttributeState::Time:
+ case HTML::HTMLInputElement::TypeAttributeState::LocalDateAndTime:
+ case HTML::HTMLInputElement::TypeAttributeState::Number:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// https://html.spec.whatwg.org/multipage/input.html#attr-input-readonly
+void HTMLInputElement::handle_readonly_attribute(DeprecatedFlyString const& value)
+{
+ // The readonly attribute is a boolean attribute that controls whether or not the user can edit the form control. When specified, the element is not mutable.
+ m_is_mutable = !(!value.is_null() && is_allowed_to_be_readonly(m_type));
+
+ if (m_text_node)
+ m_text_node->set_always_editable(m_is_mutable);
+}
+
// https://html.spec.whatwg.org/multipage/input.html#the-input-element:attr-input-placeholder-3
static bool is_allowed_to_have_placeholder(HTML::HTMLInputElement::TypeAttributeState state)
{
@@ -476,7 +508,13 @@ void HTMLInputElement::create_shadow_tree_if_needed()
MUST(m_inner_text_element->style_for_bindings()->set_property(CSS::PropertyID::Height, "1lh"sv));
m_text_node = heap().allocate(realm(), document(), initial_value);
- m_text_node->set_always_editable(m_type != TypeAttributeState::FileUpload);
+ if (m_type == TypeAttributeState::FileUpload) {
+ // NOTE: file upload state is mutable, but we don't allow the text node to be modifed
+ m_text_node->set_always_editable(false);
+ } else {
+ handle_readonly_attribute(attribute(HTML::AttributeNames::readonly));
+ }
+
m_text_node->set_owner_input_element({}, *this);
if (m_type == TypeAttributeState::Password)
@@ -541,6 +579,8 @@ void HTMLInputElement::attribute_changed(DeprecatedFlyString const& name, Deprec
} else if (name == HTML::AttributeNames::placeholder) {
if (m_placeholder_text_node)
m_placeholder_text_node->set_data(value);
+ } else if (name == HTML::AttributeNames::readonly) {
+ handle_readonly_attribute(value);
}
}
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h
index 8231d30c85..9e1536a197 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h
@@ -162,6 +162,8 @@ private:
WebIDL::ExceptionOr run_input_activation_behavior();
void set_checked_within_group();
+ void handle_readonly_attribute(DeprecatedFlyString const& value);
+
// https://html.spec.whatwg.org/multipage/input.html#value-sanitization-algorithm
DeprecatedString value_sanitization_algorithm(DeprecatedString) const;
@@ -182,6 +184,9 @@ private:
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-dirty
bool m_dirty_value { false };
+ // https://html.spec.whatwg.org/multipage/input.html#the-input-element:concept-fe-mutable
+ bool m_is_mutable { true };
+
// https://html.spec.whatwg.org/multipage/input.html#the-input-element:legacy-pre-activation-behavior
bool m_before_legacy_pre_activation_behavior_checked { false };
bool m_before_legacy_pre_activation_behavior_indeterminate { false };