Skip to content

Latest commit

 

History

History
159 lines (122 loc) · 4.82 KB

File metadata and controls

159 lines (122 loc) · 4.82 KB

← Back to docs

CSS Selectors

JustHTML supports a comprehensive subset of CSS selectors for querying the DOM.

Performance Notes

  • Selector parsing is cached internally (LRU, up to 512 distinct selector strings). Repeating the same selector across many calls avoids re-parsing overhead.
  • Simple tag-only selectors like "div" use a fast path (descendant scan without running the full selector matcher).
  • If you generate lots of unique selectors dynamically, expect some parse overhead once the cache churns.

Basic Selectors

Selector Example Description
Tag div Elements by tag name
Class .intro Elements with class
ID #main Element with ID
Universal * All elements
doc.query("div")       # All <div> elements
doc.query_one("div")   # First matching <div>, or None

doc.query(".intro")    # All elements with class="intro"
doc.query("#main")     # Element with id="main"
doc.query("*")         # All elements

Attribute Selectors

Selector Example Description
Has attribute [href] Elements with attribute
Exact match [type="text"] Exact attribute value
Starts with [href^="https"] Attribute starts with value
Ends with [href$=".pdf"] Attribute ends with value
Contains [href*="example"] Attribute contains value
Word match [class~="active"] Space-separated word match
Prefix match [lang|="en"] Value or value followed by -
doc.query("[href]")              # All elements with href attribute
doc.query('[type="submit"]')     # Exact match
doc.query('[href^="https://"]')  # Links starting with https://
doc.query('[src$=".png"]')       # Images ending with .png
doc.query('[class*="btn"]')      # Classes containing "btn"

Combinators

Combinator Example Description
Descendant div p <p> anywhere inside <div>
Child div > p <p> direct child of <div>
Adjacent h1 + p <p> immediately after <h1>
Sibling h1 ~ p Any <p> sibling after <h1>
doc.query("div p")          # Paragraphs anywhere in a div
doc.query("ul > li")        # Direct list items
doc.query("h1 + p")         # First paragraph after h1
doc.query("h1 ~ p")         # All paragraphs after h1

Pseudo-classes

Structural

Selector Description
:first-child First child of parent
:last-child Last child of parent
:only-child Only child of parent
:nth-child(n) Nth child (1-indexed)
:nth-last-child(n) Nth child from end
:first-of-type First of its type in parent
:last-of-type Last of its type in parent
:only-of-type Only of its type in parent
:nth-of-type(n) Nth of its type
:nth-last-of-type(n) Nth of its type from end
doc.query("li:first-child")       # First list item
doc.query("li:last-child")        # Last list item
doc.query("li:nth-child(2)")      # Second list item
doc.query("li:nth-child(odd)")    # Odd list items (1st, 3rd, 5th...)
doc.query("li:nth-child(even)")   # Even list items (2nd, 4th, 6th...)
doc.query("li:nth-child(3n)")     # Every 3rd item
doc.query("li:nth-child(3n+1)")   # 1st, 4th, 7th... (formula: An+B)

Content

Selector Description
:empty Elements with no children
:root Document root element
:contains("text") Non-standard (jQuery-style): elements whose descendant text contains text
:comment Non-standard: comment nodes (#comment)
doc.query("p:empty")    # Empty paragraphs
doc.query(":root")      # The <html> element
doc.query(":comment")   # Comment nodes

Negation

Selector Description
:not(selector) Elements not matching selector
doc.query("div:not(.hidden)")     # Visible divs
doc.query("input:not([disabled])")  # Enabled inputs

Selector Groups

Combine multiple selectors with commas:

doc.query("h1, h2, h3")           # All headings
doc.query(".btn, [type='submit']") # Buttons and submit inputs

Compound Selectors

Chain selectors without spaces:

doc.query("div.container")        # <div class="container">
doc.query("input[type='text']")   # <input type="text">
doc.query("li.active:first-child") # First li with class active

Examples

# Navigation links
doc.query("nav a")

# Active menu item
doc.query("nav li.active > a")

# Form inputs except hidden
doc.query("form input:not([type='hidden'])")

# Alternating table rows
doc.query("tr:nth-child(even)")

# First paragraph in each container
doc.query("div > p:first-of-type")

# External links
doc.query('a[href^="http"]:not([href*="mysite.com"])')