diff --git a/Libraries/LibWeb/HTML/AttributeNames.h b/Libraries/LibWeb/HTML/AttributeNames.h
index 446c9ade1e7..1afe13b69ee 100644
--- a/Libraries/LibWeb/HTML/AttributeNames.h
+++ b/Libraries/LibWeb/HTML/AttributeNames.h
@@ -286,6 +286,7 @@ namespace AttributeNames {
__ENUMERATE_HTML_ATTRIBUTE(sizes, "sizes") \
__ENUMERATE_HTML_ATTRIBUTE(slot, "slot") \
__ENUMERATE_HTML_ATTRIBUTE(span, "span") \
+ __ENUMERATE_HTML_ATTRIBUTE(spellcheck, "spellcheck") \
__ENUMERATE_HTML_ATTRIBUTE(src, "src") \
__ENUMERATE_HTML_ATTRIBUTE(srcdoc, "srcdoc") \
__ENUMERATE_HTML_ATTRIBUTE(srclang, "srclang") \
diff --git a/Libraries/LibWeb/HTML/HTMLElement.cpp b/Libraries/LibWeb/HTML/HTMLElement.cpp
index c91afadc486..ac5d902f069 100644
--- a/Libraries/LibWeb/HTML/HTMLElement.cpp
+++ b/Libraries/LibWeb/HTML/HTMLElement.cpp
@@ -2133,4 +2133,66 @@ bool HTMLElement::draggable() const
return false;
}
+// https://html.spec.whatwg.org/multipage/interaction.html#dom-spellcheck
+bool HTMLElement::spellcheck() const
+{
+ // The spellcheck attribute is an enumerated attribute with the following keywords and states:
+ // Keyword | State | Brief description
+ // true | True | Spelling and grammar will be checked.
+ // (the empty string) | |
+ // false | False | and grammar will not be checked.
+
+ // The attribute's missing value default and invalid value default are both the Default state. The default state
+ // indicates that the element is to act according to a default behavior, possibly based on the parent element's
+ // own spellcheck state, as defined below.
+
+ // For each element, user agents must establish a default behavior, either through defaults or through preferences
+ // expressed by the user. There are three possible default behaviors for each element:
+
+ // true-by-default
+ // The element will be checked for spelling and grammar if its contents are editable and spellchecking is not
+ // explicitly disabled through the spellcheck attribute.
+ // false-by-default
+ // The element will never be checked for spelling and grammar unless spellchecking is explicitly enabled
+ // through the spellcheck attribute.
+ // inherit-by-default
+ // The element's default behavior is the same as its parent element's. Elements that have no parent element
+ // cannot have this as their default behavior.
+
+ // NOTE: We use "true-by-default" for elements which are editable, editing hosts, or form associated text control
+ // elements "false-by-default" for root elements, and "inherit-by-default" for other elements.
+
+ auto maybe_spellcheck_attribute = attribute(HTML::AttributeNames::spellcheck);
+
+ // The spellcheck IDL attribute, on getting, must return true if the element's spellcheck content attribute is in the True state,
+ if (maybe_spellcheck_attribute.has_value() && (maybe_spellcheck_attribute.value().equals_ignoring_ascii_case("true"sv) || maybe_spellcheck_attribute.value().is_empty()))
+ return true;
+
+ if (!maybe_spellcheck_attribute.has_value() || !maybe_spellcheck_attribute.value().equals_ignoring_ascii_case("false"sv)) {
+ // or if the element's spellcheck content attribute is in the Default state and the element's default behavior is true-by-default,
+ if (is_editable_or_editing_host() || is(this))
+ return true;
+
+ // or if the element's spellcheck content attribute is in the Default state and the element's default behavior is inherit-by-default
+ if (auto* parent_html_element = first_ancestor_of_type()) {
+ // and the element's parent element's spellcheck IDL attribute would return true;
+ if (parent_html_element->spellcheck())
+ return true;
+ }
+ }
+
+ // if none of those conditions applies, then the attribute must instead return false.
+ return false;
+}
+
+// https://html.spec.whatwg.org/multipage/interaction.html#dom-spellcheck
+void HTMLElement::set_spellcheck(bool spellcheck)
+{
+ // On setting, if the new value is true, then the element's spellcheck content attribute must be set to "true", otherwise it must be set to "false".
+ if (spellcheck)
+ MUST(set_attribute(HTML::AttributeNames::spellcheck, "true"_string));
+ else
+ MUST(set_attribute(HTML::AttributeNames::spellcheck, "false"_string));
+}
+
}
diff --git a/Libraries/LibWeb/HTML/HTMLElement.h b/Libraries/LibWeb/HTML/HTMLElement.h
index 33f97f32db8..492785128fa 100644
--- a/Libraries/LibWeb/HTML/HTMLElement.h
+++ b/Libraries/LibWeb/HTML/HTMLElement.h
@@ -117,6 +117,9 @@ public:
[[nodiscard]] String access_key_label() const;
+ bool spellcheck() const;
+ void set_spellcheck(bool);
+
bool fire_a_synthetic_pointer_event(FlyString const& type, DOM::Element& target, bool not_trusted);
// https://html.spec.whatwg.org/multipage/forms.html#category-label
diff --git a/Libraries/LibWeb/HTML/HTMLElement.idl b/Libraries/LibWeb/HTML/HTMLElement.idl
index 60e8e4fc6b7..743a0f89d60 100644
--- a/Libraries/LibWeb/HTML/HTMLElement.idl
+++ b/Libraries/LibWeb/HTML/HTMLElement.idl
@@ -24,7 +24,7 @@ interface HTMLElement : Element {
[Reflect=accesskey, CEReactions] attribute DOMString accessKey;
readonly attribute DOMString accessKeyLabel;
[CEReactions] attribute boolean draggable;
- [FIXME, CEReactions] attribute boolean spellcheck;
+ [CEReactions] attribute boolean spellcheck;
[FIXME, CEReactions] attribute DOMString autocapitalize;
[FIXME, CEReactions] attribute boolean autocorrect;
diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/editing/editing-0/spelling-and-grammar-checking/spellcheck-enumerated-ascii-case-insensitive.txt b/Tests/LibWeb/Text/expected/wpt-import/html/editing/editing-0/spelling-and-grammar-checking/spellcheck-enumerated-ascii-case-insensitive.txt
new file mode 100644
index 00000000000..4cdd7244625
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/html/editing/editing-0/spelling-and-grammar-checking/spellcheck-enumerated-ascii-case-insensitive.txt
@@ -0,0 +1,6 @@
+Harness status: OK
+
+Found 1 tests
+
+1 Pass
+Pass keyword false
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/editing/editing-0/spelling-and-grammar-checking/user-interaction-editing-spellcheck.txt b/Tests/LibWeb/Text/expected/wpt-import/html/editing/editing-0/spelling-and-grammar-checking/user-interaction-editing-spellcheck.txt
new file mode 100644
index 00000000000..c88bf225af1
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/html/editing/editing-0/spelling-and-grammar-checking/user-interaction-editing-spellcheck.txt
@@ -0,0 +1,8 @@
+Harness status: OK
+
+Found 3 tests
+
+3 Pass
+Pass Getting spellcheck IDL attribute
+Pass Setting spellcheck IDL attribute to true
+Pass Setting spellcheck IDL attribute to false
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/input/wpt-import/html/editing/editing-0/spelling-and-grammar-checking/spellcheck-enumerated-ascii-case-insensitive.html b/Tests/LibWeb/Text/input/wpt-import/html/editing/editing-0/spelling-and-grammar-checking/spellcheck-enumerated-ascii-case-insensitive.html
new file mode 100644
index 00000000000..c88c80b29e1
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/html/editing/editing-0/spelling-and-grammar-checking/spellcheck-enumerated-ascii-case-insensitive.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+