diff --git a/Tests/LibWeb/Ref/css-placeholder-shown-selector-ref.html b/Tests/LibWeb/Ref/css-placeholder-shown-selector-ref.html
new file mode 100644
index 0000000000..e04d3fb734
--- /dev/null
+++ b/Tests/LibWeb/Ref/css-placeholder-shown-selector-ref.html
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/Tests/LibWeb/Ref/css-placeholder-shown-selector.html b/Tests/LibWeb/Ref/css-placeholder-shown-selector.html
new file mode 100644
index 0000000000..0793a6de5c
--- /dev/null
+++ b/Tests/LibWeb/Ref/css-placeholder-shown-selector.html
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/Tests/LibWeb/Ref/manifest.json b/Tests/LibWeb/Ref/manifest.json
index c2b8f0605c..164854f8f3 100644
--- a/Tests/LibWeb/Ref/manifest.json
+++ b/Tests/LibWeb/Ref/manifest.json
@@ -9,6 +9,7 @@
"css-gradient-currentcolor.html": "css-gradient-currentcolor-ref.html",
"css-lang-selector.html": "css-lang-selector-ref.html",
"css-local-link-selector.html": "css-local-link-selector-ref.html",
+ "css-placeholder-shown-selector.html": "css-placeholder-shown-selector-ref.html",
"css-gradients.html": "css-gradients-ref.html",
"css-read-only-read-write-selectors.html": "css-read-only-read-write-selectors-ref.html",
"svg-symbol.html": "svg-symbol-ref.html",
diff --git a/Userland/Libraries/LibWeb/CSS/PseudoClasses.json b/Userland/Libraries/LibWeb/CSS/PseudoClasses.json
index 21b749d6ea..7e140eaa0b 100644
--- a/Userland/Libraries/LibWeb/CSS/PseudoClasses.json
+++ b/Userland/Libraries/LibWeb/CSS/PseudoClasses.json
@@ -95,6 +95,9 @@
"paused": {
"argument": ""
},
+ "placeholder-shown": {
+ "argument": ""
+ },
"playing": {
"argument": ""
},
diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
index 8486a66eca..f1b2c19df0 100644
--- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
+++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp
@@ -7,6 +7,7 @@
#include
#include
+#include
#include
#include
#include
@@ -497,6 +498,17 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
return !matches_read_write_pseudo_class(element);
case CSS::PseudoClass::ReadWrite:
return matches_read_write_pseudo_class(element);
+ case CSS::PseudoClass::PlaceholderShown: {
+ // https://html.spec.whatwg.org/multipage/semantics-other.html#selector-placeholder-shown
+ // The :placeholder-shown pseudo-class must match any element falling into one of the following categories:
+ // - input elements that have a placeholder attribute whose value is currently being presented to the user.
+ if (is(element) && element.has_attribute(HTML::AttributeNames::placeholder)) {
+ auto const& input_element = static_cast(element);
+ return input_element.placeholder_element() && input_element.placeholder_value().has_value();
+ }
+ // - FIXME: textarea elements that have a placeholder attribute whose value is currently being presented to the user.
+ return false;
+ }
}
return false;