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:
The attr()
function can be used with any CSS property, but support for properties other than content
is experimental.
The attr()
CSS function is used to retrieve the value of an attribute of the selected element and use it in a property value, similar to how the var()
function substitutes a custom property value. It can also be used with pseudo-elements, in which case the attribute's value on the pseudo-element's originating element is returned.
Try it
Syntax
/* Basic usage */
attr(data-count)
attr(href)
/* With type */
attr(data-width px)
attr(data-size rem)
attr(data-name 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
The attr()
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
string
keyword, atype()
function, or a CSS dimension unit. When omitted, it defaults tostring
.-
The
string
keyword parses the value into a CSS string.cssattr(data-name string, "stranger")
-
The
type()
function takes a<syntax>
as its argument that specifies what data type to parse the value into. The<syntax>
can be<angle>
,<color>
,<custom-ident>
,<image>
,<integer>
,<length>
,<length-percentage>
,<number>
,<percentage>
,<resolution>
,<string>
,<time>
,<transform-function>
, or a combination thereof.cssattr(id type(<custom-ident>), none) attr(data-count type(<number>), 0)
To accept multiple types, list all allowed
<syntax>
es in thetype()
function, separated by a|
.cssattr(data-size type(<length> | <percentage>), 0px)
For security reasons
<url>
is not allowed as a<syntax>
. -
The
<attr-unit>
identifier specifies the unit a numeric value should have (if any). It can be the%
character (percentage) or a CSS 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 of attr()
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 the guaranteed-invalid value when an <attr-type>
is set.
Description
Limitations and security
The attr()
function can reference attributes that were never intended by the page author to be used for styling, 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. You therefore can't use attr()
to dynamically construct URLs.
<!-- This won't work! -->
<span data-icon="https://example.org/icons/question-mark.svg">help</span>
<style>
span[data-icon] {
background-image: url(attr(data-icon));
}
</style>
Values that use attr()
get marked as "attr()
-tained". Using an attr()
-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 modern attr()
syntax is backwards-compatible because the old way of using it — without specifying an <attr-type>
— behaves the same as before. Having attr(data-attr)
in your code is the same as writing attr(data-attr type(<string>))
or the simpler attr(data-attr string))
.
However, there are two edge cases where the modern attr()
syntax behaves differently from the old syntax.
In the following snippet, browsers that don't support the modern attr()
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 the content
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 id="parent"><div id="child" 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 modern attr()
support there is no output.
This is because attr()
— similar to custom properties that use the var()
function — get substituted at computed value time. With the modern behavior, --x
first tries to read the data-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 a content: ;
declaration being set.
To prevent this sort of situation, don't pass inherited attr()
values onto children unless you explicitly want to.
Feature detection
You can feature detect support for modern attr()
syntax using the @supports
at-rule. In the test, try to assign advanced attr()
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 with CSS.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> ) |
string |
<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 the data-foo
data-*
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 an experimental technology
Check the Browser compatibility table carefully before using this in production.
In this example, we append the value of data-browser
data-*
global attribute to the <p>
element. If the data-browser
attribute is missing from the <p>
element, we append the fallback 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 an experimental technology
Check the Browser compatibility table carefully before using this in production.
In this example, we set the CSS value of background-color
to the value of the data-background
data-*
global attribute assigned to the <div>
element.
HTML
<div class="background" data-background="lime">
background expected to be red if your browser does not support advanced usage
of attr()
</div>
CSS
.background {
background-color: red;
}
.background[data-background] {
background-color: attr(data-background type(<color>), red);
}
Result
Using dimension units
Experimental: This is an experimental technology
Check the Browser compatibility table carefully before using this in production.
In this example the data-rotation
attribute is parsed into a deg
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
div {
width: fit-content;
transform-origin: 50% 50%;
rotate: attr(data-rotation deg, 1.5deg);
}
Result
Parsing attr()
values as <custom-ident>
s
Experimental: This is an experimental technology
Check the Browser compatibility table carefully before using this in production.
In this example, the values for the view-transition-name
property are derived from the id
attribute of the element. The attribute gets parsed into a <custom-ident>
, which is what view-transition-name
accepts as a value.
The resulting values for view-transition-name
are card-1
, card-2
, card-3
, etc.
HTML
The HTML contains four cards with different id
attributes and a "Shuffle cards" <button>
, which shuffles the cards.
<div class="cards">
<div class="card" id="card-1">1</div>
<div class="card" id="card-2">2</div>
<div class="card" id="card-3">3</div>
<div class="card" id="card-4">4</div>
</div>
<button>Shuffle cards</button>
CSS
The cards are laid out in a flex container:
.cards {
display: flex;
flex-direction: row;
gap: 1em;
padding: 1em;
}
On each card, the attr()
function gets the id
attribute and parses it into a <custom-ident>
, which is used as the value for the view-transition-name
property. When there is no id
set on a card, the fallback value none
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 the order
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 the order
update in a call to document.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 |
Browser compatibility
Report problems with this compatibility data on GitHubdesktop | mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
attr() | ||||||||||||
<fallback> | ||||||||||||
<type-or-unit> | ||||||||||||
<angle> | ||||||||||||
<color> | ||||||||||||
<frequency> | ||||||||||||
<integer> | ||||||||||||
<length> | ||||||||||||
<number> | ||||||||||||
<percentage> | ||||||||||||
<time> | ||||||||||||
<url> |
Legend
Tip: you can click/tap on a cell for more information.
- Full support
- Full support
- In development. Supported in a pre-release version.
- In development. Supported in a pre-release version.
- No support
- No support
- Experimental. Expect behavior to change in the future.
- See implementation notes.