| selectors | R Documentation |
A reference table of every combinator, simple selector, attribute
operator and pseudo-class selectr recognises: whether it is
supported, restricted to the html/xhtml translators,
never matches (a static-document limitation), or is rejected as an
error, plus the XPath a representative selector translates to. This
complements the prose in css_to_xpath, which explains
why the divergences from CSS Selectors Level 4 below exist;
this page is the flat list to check "is X supported?" against.
Every example on this page is exercised by
tests/testthat/test-selectors-reference.R against a live
css_to_xpath call, and that test also asserts every
xpath_*_pseudo, xpath_*_function and
xpath_*_combinator method of GenericTranslator and
HTMLTranslator is represented on this page, so this table
cannot silently drift from the translators' code.
| Selector | Meaning | Example XPath ("e ? f", generic) |
e f | descendant | descendant-or-self::e//f |
e > f | child | descendant-or-self::e/f |
e + f | direct adjacent sibling | descendant-or-self::e/following-sibling::*[1][self::f] |
e ~ f | indirect (general) sibling | descendant-or-self::e/following-sibling::f |
e || f | column (Selectors 4) | error - not supported, see below |
| Selector | Meaning | Example XPath |
* | universal | descendant-or-self::* |
e | type (no namespace) | descendant-or-self::e |
.class | class | ...[contains(concat(' ', normalize-space(@class), ' '), ' class ')] |
#id | ID | descendant-or-self::*[@id = 'id'] |
Class matching splits @class on XML whitespace
(space/tab/CR/LF) via normalize-space(); HTML's own
"set of space-separated tokens" also treats U+000C form feed as a
separator, which this does not - negligible in practice, since form
feed in a class attribute is vanishingly rare.
| Selector | Meaning | Example XPath ("[attr ? val]") |
[attr] | has attribute | descendant-or-self::*[@attr] |
[attr=val] | equals | descendant-or-self::*[@attr = 'val'] |
[attr~=val] | includes a whitespace-separated token | ...[contains(concat(' ', normalize-space(@attr), ' '), ' val ')] |
[attr|=val] | equals, or a "val-" prefix | ...[@attr = 'val' or starts-with(@attr, 'val-')] |
[attr^=val] | starts with | descendant-or-self::*[starts-with(@attr, 'val')] |
[attr$=val] | ends with | ...[substring(@attr, string-length(@attr)-2) = 'val'] |
[attr*=val] | contains substring | descendant-or-self::*[contains(@attr, 'val')] |
Every operator above accepts a trailing Selectors 4 case-sensitivity
flag, i (ASCII case-insensitive) or s (case-sensitive,
the default and so a no-op): [attr=val i] translates to
...[translate(@attr, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz') = 'val']. Any other flag is a parse
error.
Under the html translator, the attributes HTML lists as ASCII
case-insensitive (type, rel, lang,
hreflang, dir, media, method,
target, checked, disabled, readonly,
selected, multiple, shape, scope,
align, charset, http-equiv, enctype,
accept and the rest of HTML's "Case-sensitivity of selectors"
list) match their values that way with no flag written, as they do in
a browser: input[type=radio] selects <input
type="RADIO">. An explicit s restores the exact comparison.
class, id, href, name, data-*
and every namespaced attribute keep it, and so does every attribute
under the generic and xhtml translators, which serve
XML rather than HTML documents.
| Selector | Status | Example XPath |
:root | supported | descendant-or-self::*[not(parent::*)] |
:first-child | supported | ...[count(preceding-sibling::*) = 0] |
:last-child | supported | ...[count(following-sibling::*) = 0] |
:only-child | supported | preceding- and following-sibling counts both 0 |
e:first-of-type | supported (needs a named element) | ...e[count(preceding-sibling::e) = 0] |
e:last-of-type | supported (needs a named element) | ...e[count(following-sibling::e) = 0] |
e:only-of-type | supported (needs a named element) | preceding- and following-sibling e counts both 0 |
*:first-of-type etc. | error | needs each sibling's own name; not expressible in XPath 1.0 |
:nth-child(An+B) | supported | :nth-child(2n+1) gives ...[count(preceding-sibling::*) mod 2 = 0]; a B outside the first cycle adds a >= B-1 bound and an offset in the mod |
:nth-child(An+B of S) | supported | preceding-siblings filtered to S, plus self:: test |
:nth-last-child() | supported | as :nth-child(), counting from the end |
e:nth-of-type(), e:nth-last-of-type() | supported (needs a named element) | as above, restricted to siblings named e |
:empty | supported, Selectors 3 semantics | ...[not(*) and not(string-length())] - see "Divergences" below |
:scope | supported, leading position only | self::* (replaces the prefix); errors elsewhere in a selector |
| Selector | Meaning | Example XPath |
:not(e) | none of the arguments match | descendant-or-self::*[not(self::e)] |
:is(e, f) (alias :matches()) | any argument matches | descendant-or-self::*[self::e or self::f] |
:where(e, f) | any argument matches (zero specificity) | same XPath as :is() |
:has(> e) | a descendant/relative match exists | descendant-or-self::*[child::e] |
Each accepts a full selector list, but a :scope inside any of
them is an error (see :scope above), and the column
combinator inside them is likewise unsupported.
| Selector | Status | Notes |
:lang(range) | supported, translator-dependent | generic: XPath lang(), prefix match only. html/xhtml: RFC 4647 extended filtering for multi-subtag ranges (subtags may be skipped between the ones named, but a leading * consumes the tag's primary subtag, so :lang(*-CH) does not match lang="ch-DE"). Every translator rejects a range that is not an RFC 4647 extended language range (:lang(en-), :lang(en*)); see css_to_xpath for the full rules |
:lang("") | supported, every translator | matches an element with no content language anywhere in its ancestor-or-self chain |
:dir() | never matches, every translator | descendant-or-self::*[0]; directionality needs a live DOM (dir="auto", bdi, form controls) |
| Selector | generic | html / xhtml |
:link, :any-link | never matches | matches a and area elements with an href (a link element is metadata, not a hyperlink) |
:visited | never matches | never matches (no browser history in a static document) |
:hover, :active, :focus, :focus-within, :focus-visible | never matches | never matches (runtime UI state) |
:target, :target-within | never matches | never matches (needs the document's URL fragment) |
:local-link | never matches | never matches (needs the document's URL) |
"Never matches" translates to descendant-or-self::*[0]: valid
CSS, always zero results, rather than an error. In a larger compound
the always-false 0 absorbs the compound's other conditions,
which cannot change the outcome, so "a.external:visited"
translates to descendant-or-self::a[0] as well.
These are only meaningfully supported by the html and
xhtml translators (under generic they never match,
listed above as the general runtime-state case). Every one matches
by local name regardless of
namespace, so "*|input:disabled" works the same as
"input:disabled" on an unnamespaced document. :enabled
and :disabled match only the elements listed below - in
particular a hyperlink is not :enabled; use :link or
:any-link for links.
| Selector | Elements and condition (html/xhtml) |
:enabled / :disabled | button, input, select, textarea, optgroup, option, fieldset; a disabled ancestor fieldset disables descendants (nested fieldsets included) except inside its first legend, and a disabled select or optgroup disables the optgroups and options below it |
:checked | checked checkbox/radio inputs and selected options; does not infer the implicit default selection of an unadorned single-select or radio group |
:required / :optional | input of a type that takes required (every type but hidden, range, color, submit, image, reset and button), select, textarea, by presence of required |
:read-write | an input of a type that takes readonly (every type but hidden, color, checkbox, radio, file, submit, image, reset, button and range) or a textarea, that is not readonly/disabled; or an element whose nearest contenteditable ancestor-or-self is not "false" (only "", "true", "plaintext-only" and "false" set the state - "inherit" and unrecognised values inherit) |
:read-only | the negation of :read-write (matches everything else, e.g. a checkbox or a plain div) |
:placeholder-shown | textarea, or an input of a type that takes placeholder (every type but hidden, checkbox, radio, file, submit, image, reset, button, color, range, date, month, week, time and datetime-local), with a non-empty placeholder and an empty current value |
:default | a selected option, a checked checkbox/radio, or the first submit button in its nearest ancestor form (does not follow a form= attribute) |
Because HTML's type is an enumerated attribute, these match
its keywords ASCII case-insensitively (<input type="RADIO">
is :checked). An input with no type, or with an
unrecognised one, is in the text state, as it is for an HTML parser.
The Selectors 4 column combinator (a || b) and the column
pseudo-classes :nth-col() / :nth-last-col() are
rejected with an error: which column a cell belongs to depends on
colspan/rowspan table-layout arithmetic that XPath 1.0
cannot express.
| Selector | Meaning | Example XPath ("? p") |
p | p in no namespace | descendant-or-self::p |
d|p | p in the namespace prefix d resolves to via the ns map | descendant-or-self::d:p |
*|p | p in any namespace | descendant-or-self::*[local-name() = 'p'] |
|p | p in no namespace, spelled explicitly | descendant-or-self::p |
Prefixes such as d above are resolved through the ns
argument passed to xml_find_all /
getNodeSet at query time, not through whatever
prefix the document itself uses; see querySelectorAll.
A prefix is written into the generated XPath as it stands, so it has
to be a name XPath can parse (an XML NCName, which is not
restricted to ASCII); one that is not, such as the escaped
\31 ns|div, is rejected with an error rather than compared
against the document's own prefix. An escaped *
(\2a|div) is such a prefix too: only the delimiter *
of *|p above is the any-namespace wildcard, and a prefix
spelled by an identifier is one no @namespace rule could have
bound. Local names carry no such
restriction: one that cannot be written as a name test is compared
with local-name() instead, e.g. d|\31 becomes
d:*[local-name() = '1'].
HTMLTranslator additionally lower-cases every element and
attribute name - folding A-Z only, as an HTML parser
does, so a non-ASCII name is left as written - including namespaced
ones, so svg|linearGradient becomes
svg:lineargradient, which matches libxml2's HTML parser but
would be wrong against a tree that restores camelCase SVG/MathML
names (browsers, html5ever).
:empty keeps Selectors 3 semantics: an element
containing only white space, e.g. <p> </p>, does not match.
Selectors 4 loosened this to also match white-space-only content,
but no browser has shipped that change, so it is treated as not
implemented, tracking browser behaviour rather than the spec text.
:checked tests only @checked/@selected.
It does not infer the implicit selectedness of an option
with no selected attribute anywhere in its select
(the first option is selected by default), nor a radio group's
mutual exclusivity - both need a live DOM to resolve.
HTMLTranslator lower-cases foreign-content element and
attribute names unconditionally, targeting libxml2-style HTML
trees (see "Namespaces" above); an HTML5 parser that restores
camelCase SVG/MathML names would disagree.
Class/token matching (.foo, [attr~=val]) does
not treat U+000C form feed as whitespace, unlike HTML's ASCII
whitespace definition (see "Simple selectors" above).
Simon Potter
CSS Selectors Level 4 https://www.w3.org/TR/selectors-4/, XPath https://www.w3.org/TR/xpath/.
css_to_xpath for the full prose explanation of each
divergence above and the error classes raised for unsupported
selectors; querySelectorAll for namespace and chaining
semantics when querying a document.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.