diff --git a/Tests/LibWeb/Text/expected/DOM/Element-removeAttributeNS.txt b/Tests/LibWeb/Text/expected/DOM/Element-removeAttributeNS.txt
new file mode 100644
index 0000000000..23e5ed385f
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/DOM/Element-removeAttributeNS.txt
@@ -0,0 +1,12 @@
+ Original values
+xlink:href getAttributeNS = 'test'
+href getAttribute = 'test'
+Non-matching namespace
+xlink:href getAttributeNS = 'test'
+href getAttribute = 'test'
+Non-matching name
+xlink:href getAttributeNS = 'test'
+href getAttribute = 'test'
+Matching
+xlink:href getAttributeNS = 'null'
+href getAttribute = 'null'
diff --git a/Tests/LibWeb/Text/input/DOM/Element-removeAttributeNS.html b/Tests/LibWeb/Text/input/DOM/Element-removeAttributeNS.html
new file mode 100644
index 0000000000..2a15b57fbc
--- /dev/null
+++ b/Tests/LibWeb/Text/input/DOM/Element-removeAttributeNS.html
@@ -0,0 +1,37 @@
+
+
+
diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp
index 815408acdf..efcf598e2b 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Element.cpp
@@ -305,6 +305,13 @@ void Element::remove_attribute(FlyString const& name)
m_attributes->remove_attribute(name);
}
+// https://dom.spec.whatwg.org/#dom-element-removeattributens
+void Element::remove_attribute_ns(Optional const& namespace_, FlyString const& name)
+{
+ // The removeAttributeNS(namespace, localName) method steps are to remove an attribute given namespace, localName, and this, and then return undefined.
+ m_attributes->remove_attribute_ns(namespace_, name);
+}
+
// https://dom.spec.whatwg.org/#dom-element-hasattribute
bool Element::has_attribute(FlyString const& name) const
{
diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h
index 30bd2870a3..4644aa5639 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.h
+++ b/Userland/Libraries/LibWeb/DOM/Element.h
@@ -112,6 +112,7 @@ public:
void append_attribute(Attr&);
void remove_attribute(FlyString const& name);
+ void remove_attribute_ns(Optional const& namespace_, FlyString const& name);
WebIDL::ExceptionOr toggle_attribute(FlyString const& name, Optional force);
size_t attribute_list_size() const;
diff --git a/Userland/Libraries/LibWeb/DOM/Element.idl b/Userland/Libraries/LibWeb/DOM/Element.idl
index f4c5eb5ea3..87dec411fb 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.idl
+++ b/Userland/Libraries/LibWeb/DOM/Element.idl
@@ -35,7 +35,8 @@ interface Element : Node {
[CEReactions] Attr? setAttributeNode(Attr attr);
[CEReactions] Attr? setAttributeNodeNS(Attr attr);
- [CEReactions] undefined removeAttribute(DOMString qualifiedName);
+ [CEReactions] undefined removeAttribute([FlyString] DOMString qualifiedName);
+ [CEReactions] undefined removeAttributeNS([FlyString] DOMString? namespace, [FlyString] DOMString localName);
[CEReactions] boolean toggleAttribute(DOMString qualifiedName, optional boolean force);
boolean hasAttribute(DOMString qualifiedName);
boolean hasAttributeNS([FlyString] DOMString? namespace, [FlyString] DOMString localName);