diff --git a/Tests/LibWeb/Text/expected/DOM/Element-getAttributeNS.txt b/Tests/LibWeb/Text/expected/DOM/Element-getAttributeNS.txt
new file mode 100644
index 0000000000..62c9187a37
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/DOM/Element-getAttributeNS.txt
@@ -0,0 +1,4 @@
+ xlink:ref getAttribute = 'null'
+xlink:ref getAttributeNS = 'test'
+href getAttribute = 'test'
+href getAttributeNS = 'null'
diff --git a/Tests/LibWeb/Text/input/DOM/Element-getAttributeNS.html b/Tests/LibWeb/Text/input/DOM/Element-getAttributeNS.html
new file mode 100644
index 0000000000..b2c5d3652b
--- /dev/null
+++ b/Tests/LibWeb/Text/input/DOM/Element-getAttributeNS.html
@@ -0,0 +1,16 @@
+
+
+
diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp
index cdb7e4c6b5..a52f58449c 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Element.cpp
@@ -120,6 +120,20 @@ Optional Element::get_attribute(FlyString const& name) const
return attribute->value();
}
+// https://dom.spec.whatwg.org/#dom-element-getattributens
+Optional Element::get_attribute_ns(Optional const& namespace_, FlyString const& name) const
+{
+ // 1. Let attr be the result of getting an attribute given namespace, localName, and this.
+ auto const* attribute = m_attributes->get_attribute_ns(namespace_, name);
+
+ // 2. If attr is null, return null.
+ if (!attribute)
+ return {};
+
+ // 3. Return attr’s value.
+ return attribute->value();
+}
+
ByteString Element::deprecated_get_attribute(FlyString const& name) const
{
auto maybe_attribute = get_attribute(name);
diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h
index 7c3a0d963e..a4fa22d418 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.h
+++ b/Userland/Libraries/LibWeb/DOM/Element.h
@@ -99,6 +99,7 @@ public:
Optional attribute(FlyString const& name) const { return get_attribute(name); }
Optional get_attribute(FlyString const& name) const;
+ Optional get_attribute_ns(Optional const& namespace_, FlyString const& name) const;
ByteString deprecated_get_attribute(FlyString const& name) const;
String get_attribute_value(FlyString const& local_name, Optional const& namespace_ = {}) const;
diff --git a/Userland/Libraries/LibWeb/DOM/Element.idl b/Userland/Libraries/LibWeb/DOM/Element.idl
index 297023feb2..de4a94cd8f 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.idl
+++ b/Userland/Libraries/LibWeb/DOM/Element.idl
@@ -29,6 +29,7 @@ interface Element : Node {
readonly attribute DOMString tagName;
DOMString? getAttribute(DOMString qualifiedName);
+ DOMString? getAttributeNS([FlyString] DOMString? namespace, [FlyString] DOMString localName);
[CEReactions] undefined setAttribute(DOMString qualifiedName, DOMString value);
[CEReactions] undefined setAttributeNS([FlyString] DOMString? namespace , [FlyString] DOMString qualifiedName , DOMString value);
[CEReactions] Attr? setAttributeNode(Attr attr);