diff --git a/Tests/LibWeb/Text/expected/DOM/Element-setAttribute-capitalization.txt b/Tests/LibWeb/Text/expected/DOM/Element-setAttribute-capitalization.txt
new file mode 100644
index 00000000000..9fb69277ef0
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/DOM/Element-setAttribute-capitalization.txt
@@ -0,0 +1 @@
+
diff --git a/Tests/LibWeb/Text/expected/DOM/Element-setAttribute-name-validation.txt b/Tests/LibWeb/Text/expected/DOM/Element-setAttribute-name-validation.txt
new file mode 100644
index 00000000000..af377f1f555
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/DOM/Element-setAttribute-name-validation.txt
@@ -0,0 +1,4 @@
+OK: InvalidCharacterError: Attribute name must not be empty or contain invalid characters
+OK: InvalidCharacterError: Attribute name must not be empty or contain invalid characters
+OK: InvalidCharacterError: Attribute name must not be empty or contain invalid characters
+OK: InvalidCharacterError: Attribute name must not be empty or contain invalid characters
diff --git a/Tests/LibWeb/Text/input/DOM/Element-setAttribute-capitalization.html b/Tests/LibWeb/Text/input/DOM/Element-setAttribute-capitalization.html
new file mode 100644
index 00000000000..e4cd2208725
--- /dev/null
+++ b/Tests/LibWeb/Text/input/DOM/Element-setAttribute-capitalization.html
@@ -0,0 +1,12 @@
+
+
diff --git a/Tests/LibWeb/Text/input/DOM/Element-setAttribute-name-validation.html b/Tests/LibWeb/Text/input/DOM/Element-setAttribute-name-validation.html
new file mode 100644
index 00000000000..eb40a48cdd9
--- /dev/null
+++ b/Tests/LibWeb/Text/input/DOM/Element-setAttribute-name-validation.html
@@ -0,0 +1,21 @@
+
+
diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp
index d326d425e3f..5cf166ba853 100644
--- a/Userland/Libraries/LibWeb/DOM/Document.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Document.cpp
@@ -2628,12 +2628,13 @@ static inline bool is_valid_name_character(u32 code_point)
|| (code_point >= 0x203f && code_point <= 0x2040);
}
+// https://www.w3.org/TR/xml/#NT-Name
bool Document::is_valid_name(String const& name)
{
- auto code_points = Utf8View { name };
- auto it = code_points.begin();
- if (code_points.is_empty())
+ if (name.is_empty())
return false;
+ auto code_points = name.code_points();
+ auto it = code_points.begin();
if (!is_valid_name_start_character(*it))
return false;
diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp
index 1fb514344e3..f9b57f7782a 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Element.cpp
@@ -167,13 +167,11 @@ JS::GCPtr Element::get_attribute_node_ns(Optional const& namesp
WebIDL::ExceptionOr Element::set_attribute(FlyString const& name, String const& value)
{
// 1. If qualifiedName does not match the Name production in XML, then throw an "InvalidCharacterError" DOMException.
- // FIXME: Proper name validation
- if (name.is_empty())
- return WebIDL::InvalidCharacterError::create(realm(), "Attribute name must not be empty"_fly_string);
+ if (!Document::is_valid_name(name.to_string()))
+ return WebIDL::InvalidCharacterError::create(realm(), "Attribute name must not be empty or contain invalid characters"_fly_string);
// 2. If this is in the HTML namespace and its node document is an HTML document, then set qualifiedName to qualifiedName in ASCII lowercase.
- // FIXME: Handle the second condition, assume it is an HTML document for now.
- bool insert_as_lowercase = namespace_uri() == Namespace::HTML;
+ bool insert_as_lowercase = namespace_uri() == Namespace::HTML && document().document_type() == Document::Type::HTML;
// 3. Let attribute be the first attribute in this’s attribute list whose qualified name is qualifiedName, and null otherwise.
auto* attribute = m_attributes->get_attribute(name);