symfony/css-selector
Converts CSS selectors to XPath expressions, letting you query HTML and XML documents with familiar CSS syntax. A port of Python's cssselect library, part of the Symfony framework.
cssselect, already present transitively in any Laravel app running Dusk or symfony/dom-crawler. The build option costs engineering weeks plus permanent maintenance; the buy option costs one composer require. That asymmetry should end the debate.article.product h2.title instead of an XPath expression. That is a genuine product differentiator (lower activation energy, familiar syntax) and simultaneously the single biggest decision in this assessment: user-authored selectors convert a pure utility into an untrusted-input security boundary.->assertSee-adjacent CSS selectors than hand-written XPath. This is a developer-productivity decision, made once, that compounds across every future test.Reader::findPattern() (#65599), a nesting-depth cap on :is()/:where() (#65596), and an LRU cache added to CssSelectorConverter to stop memory exhaustion (#63400) — all denial-of-service-class, all only reachable with attacker-supplied selectors. A minimum-version pin plus a patch-SLA is a product decision, not a lockfile chore.:is()/:where() arrived in 7.1, :has() in 8.1. :hover, :focus, and ::before are unsupported and cannot be supported (no browser in the loop). Users will type them anyway. Publishing a supported-syntax contract with inline validation is a scope decision that prevents a predictable ticket queue.Adopt when:
symfony/dom-crawler, BrowserKit, or Panther — in which case the package is likely already in composer.lock, and the real decision is whether to promote it to a direct dependency, pin it, and build product surface on it.DOMDocument and want CSS-syntax querying without hand-writing XPath.:has() may be unavailable on day one. Design around this rather than argue with it.Look elsewhere — or scope more work — when:
:hover, :focus, ::before, ::after) or XPath 2.0/3.0. Neither is in scope.symfony/symfony.For executives: this is a zero-incremental-cost, MIT-licensed, Symfony-maintained component that is almost certainly already inside our application via Dusk or DomCrawler. It converts familiar CSS selectors into XPath so that our engineers — and, optionally, our customers — can target elements in HTML without learning XPath. It opens no sockets, holds no state, registers no service provider or migration, and can be removed without touching persistence or transport. The dependency itself should be sized at approximately zero engineering effort; the value we capture is entirely in the feature built on top of it — content extraction, scrape-target definition, template regression testing, or a customer-facing selector UI.
For engineering: treat it as a pure, stateless translation function, CssSelectorConverter::toXPath(), or reach it through DomCrawler's filter(). There is one seam — selector compilation — and libxml's DOMXPath does the matching. The two things that need your attention are (1) dependency pinning, because the last several patch releases fix DoS-class defects reachable only via user-authored selectors, and (2) the capability ceiling: current pseudo-class support depends on our PHP floor, and rendering pseudo-classes are out of scope by design. Enablement material is on us — the upstream docs are Symfony-component-shaped, with no Laravel, Blade, or Dusk examples.
The honest framing: we are not adopting a dependency, we are deciding to build a feature. The dependency is hours; the feature — validation, syntax contract, error UX, ownership of upgrades — is the roadmap slot. Do not let "we added css-selector" appear on a status slide as progress toward a scraping or content-ingestion initiative. It does not fetch pages, execute JavaScript, inline styles, or sanitise markup; each of those is a separate decision with a separate owner. The one question that must be answered before committing is: who authors selectors — our engineers, or our customers? If engineers, this is a developer-ergonomics choice. If customers, it is a security-posture choice, and the required validation and pinning work grows by an order of magnitude.
How can I help you explore Laravel packages today?