How to Target xml:id Attributes with CSS Selectors
Styling raw XML directly with CSS stylesheets is a clean, lightweight approach for rendering structured data in browsers. However, targeting XML attributes that include a namespace prefix—such as xml:id—can be tricky because standard CSS attribute selectors don't treat colons as plain characters.
If you've tried foo[xml:id='bar'] or escaping the colon with foo[xml\:id='bar'] and found that it does nothing, here is an explanation of why that happens and how to fix it.
Why Doesn't xml\:id Work?
In XML, xml:id represents an attribute in the predefined XML namespace (http://www.w3.org/XML/1998/namespace). CSS does not treat the colon (:) as a regular attribute name delimiter; instead, CSS uses the pipe character (|) for namespace separation.
Depending on your requirements, there are two primary solutions to target xml:id in modern browsers.
Solution 1: Use the Standard ID Selector (Recommended)
Because the xml:id specification explicitly marks the attribute as a unique document identifier, compliant XML parsers automatically recognize it as the element's ID. Therefore, you can target it directly using the standard CSS ID selector (#):
foo#bar::after {
content: " more stuff";
}
/* Or simply target by ID */
#bar::after {
content: " more stuff";
}Note: It is best practice to use the modern double-colon pseudo-element syntax (::after) rather than the legacy single-colon syntax (:after).
Solution 2: Declare the XML Namespace in CSS
If you prefer or require an explicit attribute selector, you must declare the XML namespace using the @namespace rule and use the pipe syntax (|) instead of a colon:
@namespace xml url(http://www.w3.org/XML/1998/namespace);
foo[xml|id='bar']::after {
content: " more stuff";
}Solution 3: Use the Universal Namespace Wildcard
If you do not want to declare the namespace explicitly at the top of your stylesheet, you can use the wildcard namespace selector (*|):
foo[*|id='bar']::after {
content: " more stuff";
}This rule matches any id attribute on a <foo> element, regardless of its namespace.
Complete Working Example
Here is how your XML and CSS files should be structured together:
Document: foo.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="foo.css"?>
<foo xml:id="bar">stuff</foo>Stylesheet: foo.css
@namespace xml url(http://www.w3.org/XML/1998/namespace);
/* Both of these selectors will now work reliably */
#bar::after {
content: " more stuff";
}
foo[xml|id='bar'] {
display: block;
font-weight: bold;
}Summary
- Do not use colons or escaped colons (
xml\:id) for namespaced XML attributes in CSS. - Use standard ID selectors like
#barfor quick and universal matching. - Use
@namespace xml url(http://www.w3.org/XML/1998/namespace);combined with[xml|id='bar']for strict attribute matching.