68

I use the <details> element in my website and I want to change the design of the expand/collapse arrows. Is it possible to set a picture instead of the existing characters?

Also, is it possible to change the position of the arrows? I want it to be on the right side and not next to the summary text.

TylerH
  • 20,799
  • 66
  • 75
  • 101
benams
  • 4,308
  • 9
  • 32
  • 74

6 Answers6

87

Since <summary> has display: list-style, customising the disclosure marker can be done by setting the list-style-type property:

details > summary {
    list-style-type: '▶️';
}

details[open] > summary {
    list-style-type: '';
}

details {
    border: 1px solid gray;
    border-radius: 0.2rem;
    padding: 0.5rem;
}

details[open] > summary {
    margin-bottom: 0.5rem;
}
<details>
<summary>An example</summary>

With some example text shown when expanded.
</details>

Unfortunately some current-generation browsers (ahem, Safari …) still don’t support this. One workaround is to set list-style: none, and then provide a custom content via the ::marker pseudo-element. This can still be used to provide further customisations. Except … well, Safari also doesn’t support ::marker, it only supports the non-standard ::-webkit-details-marker. And it doesn’t support setting custom contents within it. So instead we need to hide the element and set the actual icon via ::before:

details > summary {
    list-style-type: none;
}

details > summary::-webkit-details-marker {
    display: none;
}

details > summary::before {
    content: '▶️';
}

details[open] > summary::before {
    content: '';
}

details {
    border: 1px solid gray;
    border-radius: 0.2rem;
    padding: 0.5rem;
}

details[open] > summary {
    margin-bottom: 0.5rem;
}
<details>
<summary>An example</summary>

With some example text shown when expanded.
</details>
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 1
    I don't know why, but the pseudo classes don't work for me with the tag, so I had to add a
    after every tag and to give it the style you suggested.
    – benams May 30 '12 at 13:59
  • 3
    @benams: the summary:after item needs a content: " "; attribute for it to work. – deckerdev Aug 22 '12 at 22:02
  • @konard The original answer works for images as follows: `code` details summary::-webkit-details-marker { background: url(/images/toggle-expand.gif) center no-repeat; color: transparent; } details[open] summary::-webkit-details-marker { background: url(/images/toggle-collapse.gif) center no-repeat; color: transparent; } – Ravi Menon Sep 17 '15 at 00:17
  • 1
    Nowadays `::marker` is in the standard (well, a working draft that is supported by some browsers), so you can use that instead of `::-webkit-details-marker`. https://developer.mozilla.org/en-US/docs/Web/CSS/::marker – Alien426 Jun 22 '20 at 06:58
  • @Alien426 (Depressingly) `::-webkit-details-marker` still seems to be supported more widely; even Safari supports it. By contrast, Even the most up to date version of Chrome by default does *not* support `::marker`. – Konrad Rudolph Jun 22 '20 at 09:28
  • @KonradRudolph Chrome at least now no longer requires `::-webkit-details-marker` if you want to update your answer. – TylerH Oct 26 '21 at 15:45
  • 1
    @TylerH Chrome actually hasn’t been the problem for quite some time, I think (?). The issue is that *Safari* doesn’t support `::marker` or `list-style`. But I’ve updated the answer to provide the “proper” solution at the top, and the legacy compatibility solution below. (caniuse.com seems to claim that Safari fully supports this, but that’s simply wrong.) – Konrad Rudolph Oct 27 '21 at 08:56
9

MDN says:

You can also change the style to display: block to remove the disclosure triangle.

As of 2021, this is supported by all major browsers, no need for -webkit-details-marker anymore.

You can then use the ::after pseudo-element to create a new arrow on the right side:

/* Remove the default triangle */
summary {
  display: block;
}

/* Create a new custom triangle on the right side */
summary::after {
  margin-left: 1ch;
  display: inline-block;
  content: '▶️';
  transition: 0.2s;
}

details[open] > summary::after {
  transform: rotate(90deg);
}
<details>
  <summary>Summary</summary>
  Details provided if clicked.
</details>
Jan Turoň
  • 31,451
  • 23
  • 125
  • 169
7

Is it possible to set a picture instead of the existing characters?

This is certainly possible ─ setting the baskground image to your icon and setting the original marker's colour to transparent will produce this effect.

Example:

details summary::-webkit-details-marker {
    background: url(/images/toggle-expand.png) center no-repeat;
    color: transparent;
}
details[open] summary::-webkit-details-marker {
    background: url(/images/toggle-collapse.png) center no-repeat;
    color: transparent;
}

This only works in Webkit browsers and Chrome. You might want to consider rotating the icon instead of replacing it with a different one, in which case you can use the following:

summary::--webkit-details-marker {
    transform: rotate(-90deg);
}

details[open] summary::--webkit-details-marker {
    transform: rotate(0deg);
}

[dir="rtl"] summary::--webkit-details-marker {
    transform: rotate(90deg);
}

[dir="rtl"] details[open] summary::--webkit-details-marker {
    transform: rotate(0deg);
}

This solution rotates the icon if it is originally pointing downwards. It also factors in details elements that are within RTL parents; though be careful with this approach if mutliple text directions are used throughout the document.

James Livesey
  • 129
  • 2
  • 8
Ravi Menon
  • 149
  • 1
  • 4
  • 1
    Could you please edit your answer to clarify how this answers the original question from benams? I've edited your answer to display the code block (the trick is to have a blank line before the block). – josliber Sep 17 '15 at 00:48
6

You can just add this styles

details>summary {
  list-style-type: none;
  outline: none;
  cursor: pointer;
  border: 1px solid #eee;
  padding: 5px;
  border-radius: 5px;
}

details>summary::-webkit-details-marker {
  display: none;
}

details>summary::before {
  content: '+ ';
}

details[open]>summary::before {
  content: '- ';
}

details[open]>summary {
  margin-bottom: 0.5rem;
}
<details>
  <summary>Click here</summary>
  Some text!
</details>

It is simple!

Tiago Rangel
  • 1,159
  • 15
  • 29
1

The best code I found was on http://html5doctor.com/the-details-and-summary-elements/, this neat little trick stands up. And you can put whatever you want to replace the icons in the pseudo-elements.

summary::-webkit-details-marker {
  display: none
}
summary:after {
  background: red;
  border-radius: 5px;
  content: "+";
  color: #fff;
  float: left;
  font-size: 1.5em;
  font-weight: bold;
  margin: -5px 10px 0 0;
  padding: 0;
  text-align: center;
  width: 20px;
}
details[open] summary:after {
  content: "-";
}

Picture of Code Output

Picture of Code Output

Link to a small site that you can use the dev tools on to see how it works http://output.jsbin.com/egefop/15#html,live

albert
  • 8,285
  • 3
  • 19
  • 32
Ethan
  • 19
  • 4
0

I made it work with a combination of previous answers and svg path like this while trying to represent a virtual filesystem. Hopefully useful for anyone else looking for this feature.

details>summary {
    list-style-type: none;
    cursor: pointer;
}


details>summary::before {
    content: url('data:image/svg+xml;charset=UTF-8,<svg 
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="rgb(255, 216, 104)" d="M20,6H10L8,4H2C0.9,4 0,4.9 0,6v12c0,1.1 0.9,2 
2,2h16c1.1,0 2-0.9 2-2V8c0,-1.1 -0.9,-2 -2,-2zM2,6h4l2,2h10v10H2V6z"/></svg>');
}


details[open] > summary::before {
    content: url('data:image/svg+xml;charset=UTF-8,<svg 
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="rgb(255, 216, 104)" d="M20,4v4H4V4h16m0-2H4C2.89,2 2,2.89 
2,4v16c0,1.11 0.89,2 2,2h16c1.11,0 2-0.89 2-2V8c0-1.11 -0.89-2 -2-2z"/></svg>');}

<details>
  <summary>Click here</summary>
  Some text!
</details>