diff --git a/Tests/LibWeb/Text/expected/HTML/relList-attribute.txt b/Tests/LibWeb/Text/expected/HTML/relList-attribute.txt
index 663908f1fb..b00f12b46e 100644
--- a/Tests/LibWeb/Text/expected/HTML/relList-attribute.txt
+++ b/Tests/LibWeb/Text/expected/HTML/relList-attribute.txt
@@ -10,3 +10,9 @@ area.relList for after setting rel to "whatever": whatever
area.relList for after setting rel to "prefetch": prefetch
area.relList contains "prefetch": true
area.relList contains "whatever": false
+form.relList initial length: 0
+form.relList always returns the same value: true
+form.relList for after setting rel to "whatever": whatever
+form.relList for after setting rel to "prefetch": prefetch
+form.relList contains "prefetch": true
+form.relList contains "whatever": false
diff --git a/Tests/LibWeb/Text/input/HTML/relList-attribute.html b/Tests/LibWeb/Text/input/HTML/relList-attribute.html
index 74c14c4407..2c9b03791f 100644
--- a/Tests/LibWeb/Text/input/HTML/relList-attribute.html
+++ b/Tests/LibWeb/Text/input/HTML/relList-attribute.html
@@ -18,6 +18,7 @@
const tagNamesToTest = [
"a",
"area",
+ "form",
];
for (const tagName of tagNamesToTest) {
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLFormElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLFormElement.cpp
index ef8303fd82..78b7124380 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLFormElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLFormElement.cpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -584,6 +585,15 @@ StringView HTMLFormElement::method() const
VERIFY_NOT_REACHED();
}
+// https://html.spec.whatwg.org/multipage/forms.html#dom-form-rellist
+JS::GCPtr HTMLFormElement::rel_list()
+{
+ // The relList IDL attribute must reflect the rel content attribute.
+ if (!m_rel_list)
+ m_rel_list = DOM::DOMTokenList::create(*this, HTML::AttributeNames::rel);
+ return m_rel_list;
+}
+
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-fs-method
WebIDL::ExceptionOr HTMLFormElement::set_method(String const& method)
{
@@ -611,6 +621,15 @@ WebIDL::ExceptionOr HTMLFormElement::set_action(String const& value)
return set_attribute(AttributeNames::action, value);
}
+void HTMLFormElement::attribute_changed(FlyString const& name, Optional const& value)
+{
+ HTMLElement::attribute_changed(name, value);
+ if (name == HTML::AttributeNames::rel) {
+ if (m_rel_list)
+ m_rel_list->associated_attribute_changed(value.value_or(String {}));
+ }
+}
+
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#picking-an-encoding-for-the-form
ErrorOr HTMLFormElement::pick_an_encoding() const
{
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLFormElement.h b/Userland/Libraries/LibWeb/HTML/HTMLFormElement.h
index ed40eee80d..0cc5052a98 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLFormElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLFormElement.h
@@ -92,6 +92,8 @@ public:
StringView method() const;
WebIDL::ExceptionOr set_method(String const&);
+ JS::GCPtr rel_list();
+
String action() const;
WebIDL::ExceptionOr set_action(String const&);
@@ -109,6 +111,8 @@ private:
virtual Vector supported_property_names() const override;
virtual bool is_supported_property_index(u32) const override;
+ virtual void attribute_changed(FlyString const& name, Optional const& value) override;
+
ErrorOr pick_an_encoding() const;
ErrorOr mutate_action_url(URL::URL parsed_action, Vector entry_list, String encoding, JS::NonnullGCPtr target_navigable, Bindings::NavigationHistoryBehavior history_handling, UserNavigationInvolvement user_involvement);
@@ -143,6 +147,8 @@ private:
// Each form element has a planned navigation, which is either null or a task; when the form is first created,
// its planned navigation must be set to null.
JS::GCPtr m_planned_navigation;
+
+ JS::GCPtr m_rel_list;
};
}
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLFormElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLFormElement.idl
index e413f38f4f..e4b513aebc 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLFormElement.idl
+++ b/Userland/Libraries/LibWeb/HTML/HTMLFormElement.idl
@@ -17,7 +17,7 @@ interface HTMLFormElement : HTMLElement {
[CEReactions, Reflect=novalidate] attribute boolean noValidate;
[CEReactions, Reflect] attribute DOMString target;
[CEReactions, Reflect] attribute DOMString rel;
- // FIXME: [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
+ [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
[SameObject] readonly attribute HTMLFormControlsCollection elements;
readonly attribute unsigned long length;