attr()
Baseline Widely available *
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
* Some parts of this feature may have varying levels of support.
Note:Theattr() function can be used with any CSS property, but support for properties other thancontent is experimental.
Theattr()CSSfunction is used to retrieve the value of an attribute of the selected element and use it in a property value, similar to how thevar() function substitutes a custom property value. It can also be used withpseudo-elements, in which case the attribute's value on the pseudo-element's originating element is returned.
In this article
Try it
blockquote { margin: 1em 0;}blockquote::after { display: block; content: " (source: " attr(cite) ") "; color: hotpink;}<blockquote cite="https://mozilla.org/en-US/about/"> Mozilla is working to put control of the internet back in the hands of the people using it.</blockquote><blockquote cite="https://web.dev/about/"> Build beautiful, accessible, fast, and secure websites that work cross-browser.</blockquote>Syntax
/* Basic usage */attr(data-count)attr(href)/* With type */attr(data-width px)attr(data-size rem)attr(data-name raw-string)attr(id type(<custom-ident>))attr(data-count type(<number>))attr(data-size type(<length> | <percentage>))/* With fallback */attr(data-count type(<number>), 0)attr(data-width px, inherit)attr(data-something, "default")Parameters
Theattr() function's syntax is as follows:
attr(<attr-name> <attr-type>? , <fallback-value>?)
The parameters are:
<attr-name>The attribute name whose value should be retrieved from the selected HTML element(s).
<attr-type>Specifies how the attribute value is parsed into a CSS value. This can be the
raw-stringkeyword, atype()function, or a CSS dimension unit (specified using an<attr-unit>identifier). When omitted, it defaults toraw-string.raw-stringThe
raw-stringkeyword causes the attribute's literal value to be treated as the value of a CSS string, with no CSS parsing performed (including CSS escapes, whitespace removal, comments, etc). The<fallback-value>is only used if the attribute is omitted; specifying an empty value doesn't trigger the fallback.cssattr(data-name raw-string, "stranger")Note:This keyword was originally named and supported in Chromium browsers as
string. Both keywords will be supported briefly, for backward compatibility purposes.type()The
type()function takes a<syntax>as its argument that specifies what data type to parse the value into.Note:Forsecurity reasons
<url>is not allowed as anattr()data type.<attr-unit>The
<attr-unit>identifier specifies the unit a numeric value should have (if any). It can be the%character (percentage) or aCSS distance unit such aspx,rem,deg,s, etc.cssattr(data-size rem)attr(data-width px, inherit)attr(data-rotation deg)
<fallback-value>The value to be used if the specified attribute is missing or contains an invalid value.
Return value
The return value ofattr() is the value of the HTML attribute whose name is<attr-name> parsed as the given<attr-type> or parsed as a CSS string.
When an<attr-type> is set,attr() will try to parse the attribute into that specified<attr-type> and return it. If the attribute cannot be parsed into the given<attr-type>, the<fallback-value> will be returned instead. When no<attr-type> is set, the attribute will be parsed into a CSS string.
If no<fallback-value> is set, the return value will default to an empty string when no<attr-type> is set or theguaranteed-invalid value when an<attr-type> is set.
Description
>Limitations and security
Theattr() function can reference attributes that were never intended for styling use and might contain sensitive information (for example, a security token used by scripts on the page). In general, this is fine, but it can become a security threat when used in URLs. Therefore, you can't useattr() to dynamically construct URLs.
<!-- This won't work! --><span data-icon="https://example.org/icons/question-mark.svg">help</span>span[data-icon] { background-image: url(attr(data-icon));}However, this restriction applies only to places that strictly require a<url> type.Some functions — such asimage-set() — can accept a<string> value that is later interpreted as a URL, allowingattr() to work in those contexts, depending on browser support:
span[data-icon] { background: image-set(attr(data-icon));}Values that useattr() get marked asattr()-tainted. Using anattr()-tainted value as or in a<url> makes a declaration become"invalid at computed value time" or IACVT for short.
Backwards compatibility
Generally speaking, the modernattr() syntax is backward-compatible because the old way of using it — without specifying an<attr-type> — behaves the same as before. Havingattr(data-attr) in your code is the same as writingattr(data-attr type(<string>)) or the simplerattr(data-attr string)).
However, there are two edge cases where the modernattr() syntax behaves differently from the old syntax.
In the following snippet, browsers that don't support the modernattr() syntax will discard the second declaration because they cannot parse it. The result in those browsers is"Hello World".
<div text="Hello"></div>div::before { content: attr(text) " World";}div::before { content: attr(text) 1px;}In browsers with support for the modern syntax, the output will be … nothing. Those browsers will successfully parse the second declaration, but because it is invalid content for thecontent property, the declaration becomes"invalid at computed value time" or IACVT for short.
To prevent this kind of situation,feature detection is recommended.
A second edge case is the following:
<div><div data-attr="foo"></div></div>#parent { --x: attr(data-attr);}#child::before { content: var(--x);}Browsers without support for modern syntax display the text"foo". In browsers with modernattr() support there is no output.
This is becauseattr() — similar to custom properties that use thevar() function — gets substituted atcomputed value time. With the modern behavior,--x first tries to read thedata-attr attribute from the#parent element, which results in an empty string because there is no such attribute on#parent. That empty string then gets inherited by the#child element, resulting in acontent: ; declaration being set.
To prevent this sort of situation, don't pass inheritedattr() values onto children unless you explicitly want to.
Feature detection
You can feature detect support for modernattr() syntax using the@supports at-rule. In the test, try to assign an advancedattr() to a (non-custom) CSS property.
For example:
@supports (x: attr(x type(*))) { /* Browser has modern attr() support */}@supports not (x: attr(x type(*))) { /* Browser does not have modern attr() support */}We can perform the same check in JavaScript withCSS.supports():
if (CSS.supports("x: attr(x type(*))")) { /* Browser has modern attr() support */}if (!CSS.supports("x: attr(x type(*))")) { /* Browser does not have modern attr() support */}Formal syntax
<attr()> =
attr(<attr-name><attr-type>? ,<declaration-value>?)
<attr-name> =
[<ident-token>? '|']?<ident-token>
<attr-type> =
type(<syntax>)|
raw-string|
number|
<attr-unit>
<syntax> =
'*'|
<syntax-component>[<syntax-combinator><syntax-component>]*|
<syntax-string>
<syntax-component> =
<syntax-single-component><syntax-multiplier>?|
'<'transform-list '>'
<syntax-combinator> =
'|'
<syntax-string> =
<string>
<syntax-single-component> =
'<'<syntax-type-name> '>'|
<ident>
<syntax-multiplier> =
'#'|
'+'
<syntax-type-name> =
angle|
color|
custom-ident|
image|
integer|
length|
length-percentage|
number|
percentage|
resolution|
string|
time|
url|
transform-function
Examples
>content property
In this example, we prepend the value of thedata-foodata-*global attribute to the contents of the<p> element.
HTML
<p data-foo="hello">world</p>CSS
[data-foo]::before { content: attr(data-foo) " ";}Result
Using a fallback value
Experimental:This is anexperimental technology
Check theBrowser compatibility table carefully before using this in production.
In this example, we append the value ofdata-browserdata-*global attribute to the<p> element. If thedata-browser attribute is missing from the<p> element, we append thefallback value of "Unknown".
HTML
<p data-browser="Firefox">My favorite browser is:</p><p>Your favorite browser is:</p>CSS
p::after { content: " " attr(data-browser, "Unknown"); color: tomato;}Result
color value
Experimental:This is anexperimental technology
Check theBrowser compatibility table carefully before using this in production.
In this example, we set the CSS value ofbackground-color to the value of thedata-backgrounddata-*global attribute assigned to the<div> element.
HTML
<div data-background="lime"> background expected to be red if your browser does not support advanced usage of attr()</div>CSS
.background { height: 100vh;}.background { background-color: red;}.background[data-background] { background-color: attr(data-background type(<color>), red);}Result
Using dimension units
Experimental:This is anexperimental technology
Check theBrowser compatibility table carefully before using this in production.
In this example thedata-rotation attribute is parsed into adeg unit, which specifies the element's rotation.
HTML
<div data-rotation="-3">I am rotated by -3 degrees</div><div data-rotation="2">And I by 2 degrees</div><div>And so am I, using the fallback value of 1.5deg</div>CSS
body { min-height: 100svh; display: grid; place-content: center; gap: 1em;}div { margin: 0 auto; border: 1px solid; border-radius: 0.25em; padding: 0.5em;}div { width: fit-content; transform-origin: 50% 50%; rotate: attr(data-rotation deg, 1.5deg);}Result
Parsingattr() values as<custom-ident>s
Experimental:This is anexperimental technology
Check theBrowser compatibility table carefully before using this in production.
In this example, the values for theview-transition-name property are derived from theid attribute of the element. The attribute gets parsed into a<custom-ident>, which is whatview-transition-name accepts as a value.
The resulting values forview-transition-name arecard-1,card-2,card-3, etc.
HTML
The HTML contains four cards with differentid attributes and a "Shuffle cards"<button>, which shuffles the cards.
<div> <div>1</div> <div>2</div> <div>3</div> <div>4</div></div><button>Shuffle cards</button><div> <p> Your browser does not support advanced <code>attr()</code>. As a result, this demo won’t do anything. </p></div>CSS
The cards are laid out in a flex container:
.cards { display: flex; flex-direction: row; gap: 1em; padding: 1em;}:root { view-transition-name: none;}::view-transition { pointer-events: none;}@supports (x: attr(x type(*))) { .warning { display: none; }}@layer layout { .card { border-radius: 0.25em; width: 20vw; max-width: 5em; aspect-ratio: 1 / 1.6; background: lightgrey; display: grid; place-content: center; font-size: 2em; } * { box-sizing: border-box; } body { min-height: 100svh; display: grid; place-content: center; } button { justify-self: center; }}@layer warning { .warning { padding: 1em; border: 1px solid #cccccc; background: rgb(255 255 205 / 0.8); text-align: center; order: -1; margin: 1em; } .warning > :first-child { margin-top: 0; } .warning > :last-child { margin-bottom: 0; }}On each card, theattr() function gets theid attribute and parses it into a<custom-ident>, which is used as the value for theview-transition-name property. When there is noid set on a card, the fallback valuenone is used instead.
.card { view-transition-name: attr(id type(<custom-ident>), none); view-transition-class: card;}JavaScript
When the<button> is pressed, the cards are shuffled. This is done by randomizing the order of an array containing references to all the cards and then updating theorder property of each card to its new array index position.
To animate each card to its new position,View Transitions are used. This is done by wrapping theorder update in a call todocument.startViewTransition.
const shuffle = (array) => { for (let i = array.length - 1; i >= 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; }};document.querySelector("button").addEventListener("click", (e) => { const $cards = Array.from(document.querySelectorAll(".card")); shuffle($cards); document.startViewTransition(() => { $cards.forEach(($card, i) => { $card.style.setProperty("order", i); }); });});Result
Specifications
| Specification |
|---|
| CSS Values and Units Module Level 5> # attr-notation> |