diff --git a/Tests/LibWeb/Text/expected/css/CSSStyleSheet-addRule.txt b/Tests/LibWeb/Text/expected/css/CSSStyleSheet-addRule.txt
new file mode 100644
index 0000000000..e820aa8385
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/css/CSSStyleSheet-addRule.txt
@@ -0,0 +1,9 @@
+addValue() return value: -1
+Rule count after calling addRule() with no arguments: 1
+Rule text: undefined { }
+Rule count after calling addRule with no index: 2
+Second rule text: .test { font-size: 14px; }
+Rule count after calling addRule with index 0: 3
+Rule text: .test { padding: 100px; }
+Exception thrown when given a negative index: IndexSizeError
+Exception thrown when index out of range: IndexSizeError
diff --git a/Tests/LibWeb/Text/input/css/CSSStyleSheet-addRule.html b/Tests/LibWeb/Text/input/css/CSSStyleSheet-addRule.html
new file mode 100644
index 0000000000..d46381ac5f
--- /dev/null
+++ b/Tests/LibWeb/Text/input/css/CSSStyleSheet-addRule.html
@@ -0,0 +1,28 @@
+
+
+
diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp
index 3d5d43f4df..2f4a5eaff7 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp
+++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp
@@ -257,6 +257,34 @@ WebIDL::ExceptionOr CSSStyleSheet::replace_sync(StringView text)
return {};
}
+// https://drafts.csswg.org/cssom/#dom-cssstylesheet-addrule
+WebIDL::ExceptionOr CSSStyleSheet::add_rule(Optional selector, Optional style, Optional index)
+{
+ // 1. Let rule be an empty string.
+ StringBuilder rule;
+
+ // 2. Append selector to rule.
+ if (selector.has_value())
+ rule.append(selector.release_value());
+
+ // 3. Append " { " to rule.
+ rule.append('{');
+
+ // 4. If block is not empty, append block, followed by a space, to rule.
+ if (style.has_value() && !style->is_empty())
+ rule.appendff("{} ", style.release_value());
+
+ // 5. Append "}" to rule.
+ rule.append('}');
+
+ // 6. Let index be optionalIndex if provided, or the number of CSS rules in the stylesheet otherwise.
+ // 7. Call insertRule(), with rule and index as arguments.
+ TRY(insert_rule(rule.string_view(), index.value_or(rules().length())));
+
+ // 8. Return -1.
+ return -1;
+}
+
// https://www.w3.org/TR/cssom/#dom-cssstylesheet-removerule
WebIDL::ExceptionOr CSSStyleSheet::remove_rule(unsigned index)
{
diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h
index b47181e1d6..0621f9a535 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h
+++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
namespace Web::CSS {
@@ -49,6 +50,7 @@ public:
CSSRuleList const* css_rules() const { return m_rules; }
WebIDL::ExceptionOr insert_rule(StringView rule, unsigned index);
+ WebIDL::ExceptionOr add_rule(Optional selector, Optional style, Optional index);
WebIDL::ExceptionOr remove_rule(unsigned index);
WebIDL::ExceptionOr delete_rule(unsigned index);
diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.idl b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.idl
index cd424853ad..8dcce0584f 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.idl
+++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.idl
@@ -18,7 +18,7 @@ interface CSSStyleSheet : StyleSheet {
// https://drafts.csswg.org/cssom/#legacy-css-style-sheet-members
[SameObject, ImplementedAs=css_rules] readonly attribute CSSRuleList rules;
- // FIXME: long addRule(optional DOMString selector = "undefined", optional DOMString style = "undefined", optional unsigned long index);
+ long addRule(optional DOMString selector = "undefined", optional DOMString style = "undefined", optional unsigned long index);
undefined removeRule(unsigned long index);
};