diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp
index bd17b8554587..c406c2ba3420 100644
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -269,6 +269,76 @@ void nsGenericHTMLElement::GetAccessKeyLabel(nsString& aLabel) {
}
}
+// https://html.spec.whatwg.org/#dom-hidden
+void nsGenericHTMLElement::GetHidden(
+ Nullable& aHidden) const {
+ OwningBooleanOrUnrestrictedDoubleOrString value;
+ // 1. If the hidden attribute is in the hidden until found state, then
+ // return "until-found".
+ nsAutoString result;
+ if (GetAttr(kNameSpaceID_None, nsGkAtoms::hidden, result)) {
+ if (StaticPrefs::dom_hidden_until_found_enabled() &&
+ result.LowerCaseEqualsLiteral("until-found")) {
+ value.SetStringLiteral(u"until-found");
+ } else {
+ // 2. If the hidden attribute is set, then return true.
+ value.SetAsBoolean() = true;
+ }
+ } else {
+ // 3. Return false.
+ value.SetAsBoolean() = false;
+ }
+
+ aHidden.SetValue(value);
+}
+
+// https://html.spec.whatwg.org/#dom-hidden
+void nsGenericHTMLElement::SetHidden(
+ const Nullable& aHidden,
+ ErrorResult& aRv) {
+ // 4. Otherwise, if the given value is null, then remove the hidden attribute.
+ if (aHidden.IsNull()) {
+ return UnsetAttr(nsGkAtoms::hidden, aRv);
+ }
+ bool isHidden = true;
+ const auto& value = aHidden.Value();
+ // 1. If the given value is a string that is an ASCII case-insensitive match
+ // for "until-found", then set the hidden attribute to "until-found".
+ if (value.IsString()) {
+ const nsAString& stringValue = value.GetAsString();
+ // 3. Otherwise, if the given value is the empty string, then remove the
+ // hidden attribute.
+ if (stringValue.IsEmpty()) {
+ isHidden = false;
+ } else if (StaticPrefs::dom_hidden_until_found_enabled() &&
+ stringValue.LowerCaseEqualsLiteral("until-found")) {
+ return SetAttr(nsGkAtoms::hidden, u"until-found"_ns, aRv);
+ }
+ }
+ // 2. Otherwise, if the given value is false, then remove the hidden
+ // attribute.
+ else if (value.IsBoolean()) {
+ if (!value.GetAsBoolean()) {
+ isHidden = false;
+ }
+ }
+ // 5. Otherwise, if the given value is 0, then remove the hidden attribute.
+ // 6. Otherwise, if the given value is NaN, then remove the hidden attribute.
+ else if (value.IsUnrestrictedDouble()) {
+ double d = value.GetAsUnrestrictedDouble();
+ if (d == 0.0 || std::isnan(d)) {
+ isHidden = false;
+ }
+ }
+
+ // 7. Otherwise, set the hidden attribute to the empty string.
+ if (isHidden) {
+ aRv = SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, u""_ns, true);
+ } else {
+ aRv = UnsetAttr(kNameSpaceID_None, nsGkAtoms::hidden, true);
+ }
+}
+
static bool IsOffsetParent(nsIFrame* aFrame) {
LayoutFrameType frameType = aFrame->Type();
diff --git a/dom/html/nsGenericHTMLElement.h b/dom/html/nsGenericHTMLElement.h
index 66ec09e6daf0..43276ff6840c 100644
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -14,6 +14,7 @@
#include "nsContentCreatorFunctions.h"
#include "nsStyledElement.h"
#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/DOMRect.h"
#include "mozilla/dom/ValidityState.h"
@@ -95,10 +96,16 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase {
void SetPopover(const nsAString& aPopover, mozilla::ErrorResult& aError) {
SetOrRemoveNullableStringAttr(nsGkAtoms::popover, aPopover, aError);
}
- bool Hidden() const { return GetBoolAttr(nsGkAtoms::hidden); }
- void SetHidden(bool aHidden, mozilla::ErrorResult& aError) {
- SetHTMLBoolAttr(nsGkAtoms::hidden, aHidden, aError);
- }
+
+ void GetHidden(mozilla::dom::Nullable<
+ mozilla::dom::OwningBooleanOrUnrestrictedDoubleOrString>&
+ aHidden) const;
+
+ void SetHidden(
+ const mozilla::dom::Nullable<
+ mozilla::dom::BooleanOrUnrestrictedDoubleOrString>& aHidden,
+ mozilla::ErrorResult& aRv);
+
bool Inert() const { return GetBoolAttr(nsGkAtoms::inert); }
void SetInert(bool aInert, mozilla::ErrorResult& aError) {
SetHTMLBoolAttr(nsGkAtoms::inert, aInert, aError);
diff --git a/dom/webidl/HTMLElement.webidl b/dom/webidl/HTMLElement.webidl
index c0922f7b7a98..a112fec8e899 100644
--- a/dom/webidl/HTMLElement.webidl
+++ b/dom/webidl/HTMLElement.webidl
@@ -33,7 +33,7 @@ interface HTMLElement : Element {
// user interaction
[CEReactions, SetterThrows, Pure]
- attribute boolean hidden;
+ attribute (boolean or unrestricted double or DOMString)? hidden;
[CEReactions, SetterThrows, Pure]
attribute boolean inert;
[NeedsCallerType]
diff --git a/testing/web-platform/meta/html/editing/the-hidden-attribute/__dir__.ini b/testing/web-platform/meta/html/editing/the-hidden-attribute/__dir__.ini
new file mode 100644
index 000000000000..a15e737e44c3
--- /dev/null
+++ b/testing/web-platform/meta/html/editing/the-hidden-attribute/__dir__.ini
@@ -0,0 +1 @@
+prefs: [dom.hidden_until_found.enabled:true]
\ No newline at end of file
diff --git a/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-idl.html.ini b/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-idl.html.ini
deleted file mode 100644
index 3e5a92d47b2f..000000000000
--- a/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-idl.html.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[hidden-idl.html]
- [div.hidden = "until-found"]
- expected: FAIL
-
- [div.hidden = "UNTIL-FOUND"]
- expected: FAIL
-
- [div.hidden = "UnTiL-FoUnD"]
- expected: FAIL
diff --git a/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-until-found-007.html.ini b/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-until-found-007.html.ini
deleted file mode 100644
index ea525afbaf24..000000000000
--- a/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-until-found-007.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[hidden-until-found-007.html]
- expected: FAIL
diff --git a/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-until-found-idl.html.ini b/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-until-found-idl.html.ini
deleted file mode 100644
index 1505f47bcd43..000000000000
--- a/testing/web-platform/meta/html/editing/the-hidden-attribute/hidden-until-found-idl.html.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[hidden-until-found-idl.html]
- [element.hidden should return "until-found" regardless of uppercase letters.]
- expected: FAIL
diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py
index e060f6cd2009..26af767ade95 100644
--- a/xpcom/ds/StaticAtoms.py
+++ b/xpcom/ds/StaticAtoms.py
@@ -1302,6 +1302,7 @@ STATIC_ATOMS = [
Atom("u", "u"),
Atom("ul", "ul"),
Atom("unparsedEntityUri", "unparsed-entity-uri"),
+ Atom("untilFound", "until-found"),
Atom("up", "up"),
Atom("update", "update"),
Atom("upperFirst", "upper-first"),