Buttons

Each arXiv button family shares the same mechanical spec, with color used to differentiate by context: Open Blue for public pages and Access Lime for internal tools. Public pages are everywhere a reader or author can access. Internal pages include arXiv Check and the Admin Console.

Button tiers

arXiv has three button tiers: primary, secondary, and a quiet text-only button (text links can be found on the typography page).

Note

When to use a text button vs a text link: Use a text button for actions that do not navigate to a new page. Use a text link when navigating to a new page or to an anchor link on the same page.

Public
Internal
Disabled
Destructive
Relevant code
ClassFillUse for
.ds-btn-primaryOpen Blue #a5d6feThe page's call to action (HTML, PDF on the abstract page). One cluster per view.
.ds-btnWhite, warm-grey gradient borderAdjacent destinations of equal weight but lower priority (TeX Source).
.ds-btn-textNone — no fill, no border, no shadowReal but minor actions beside a bigger choice: Copy link, Show all authors, Dismiss.
Construction
Both filled variants share the V3 build: a 1.5px gradient border (lighter top → darker bottom) from dual padding-box/border-box backgrounds, plus an inner vignette. Hover brightens; press drops 1px and deepens the vignette.
Quiet tier
The text button borrows the link’s quietness, not its identity: Link Blue, never underlined, and hover is a background wash — the same feedback the other buttons give. Underlines stay with links, so a reader can still tell “this navigates” from “this acts here.”
No outline tier
The secondary is already white fill plus border, and on a white canvas a transparent fill is the same pixels as a white one.
Icons
Any .ds-btn accepts an inline SVG. The stylesheet sizes it in em, blocks the baseline gap, and stops it shrinking beside a long label. Set stroke="currentColor" and nothing else.
Disabled
One flat --ds-tint-warm fill for every variant. An action that is merely not available yet takes aria-disabled instead — see Forms.
<!-- Primary / secondary / text -->
<a class="ds-btn ds-btn-primary" href="/html/2604.22725v1">HTML</a>
<a class="ds-btn" href="/src/2604.22725v1">TeX Source</a>
<button class="ds-btn ds-btn-text" type="button">Copy link</button>

Never mix the two primary accent colors

An Access Lime primary button on a public page, or an Open Blue button in an internal tool, is a policy violation. If the context is ambiguous, settle it first and record the answer in a code comment.

A control that goes to another page is a link, even when it looks like a button. The formats on the abstract page are the common case: each one is an <a> with the button classes, so it announces as a link, opens in a new tab, and works with JavaScript off.

Note

A link cannot take the disabled attribute. To disable one, add .is-disabled, remove the href, and add aria-disabled. With the href still there the link still works while looking switched off.

Internal
Disabled
Relevant code
<a class="ds-btn ds-btn-primary" href="/html/2604.22725v1">HTML</a>
<a class="ds-btn" href="/pdf/2604.22725v1">PDF</a>

<!-- disabled: no href, and both the class and the attribute -->
<a class="ds-btn is-disabled" aria-disabled="true">Other formats</a>
.ds-btn, .ds-btn-primary, .ds-btn-text
The same classes as a button. Nothing about the link changes how they look.
.is-disabled
Gives a link the disabled look, the same as disabled gives a button. It only changes the look: remove the href so the link stops working, and add aria-disabled="true" so a screen reader says so.

Small actions attached to content

This component is a variant of text-only buttons and attach a row of tiny controls to a content element. It is used on the HTML papers page for figures, formula, and more. They differ from default text-only buttons via their font size, color, and surrounding container. They appear when hovering over the parent element.

(This content might be a figure, a formula, or other content with additional options to surface for users)
Relevant code
<figure class="fig-wrap" style="position: relative;">
  <!-- the figure, formula, or other content -->
  <div class="ds-element-pill" role="toolbar" aria-label="Figure 1" style="bottom: -14px; left: 50%; transform: translateX(-50%);">
    <button type="button"><svg aria-hidden="true">…</svg> Permalink</button>
    <button type="button"><svg aria-hidden="true">…</svg> Alt text</button>
    <button type="button"><svg aria-hidden="true">…</svg> Expand</button>
  </div>
</figure>
<script src="element-pill.js" defer></script>
.ds-element-pill
The container: a white pill straddling the bottom edge of the content it belongs to. The wrapper supplies position: relative; the pill positions itself inside it.
.is-revealed
The pill is hidden at rest and shown while the wrapped content is hovered or holds focus. The consumer adds and removes this class; the demo above keeps it on. The pill also shows whenever one of its own actions has keyboard focus. The pill fades in, and under prefers-reduced-motion it appears without the fade.
role="toolbar", aria-label
The pill is one tab stop. Tab reaches its first action, or the one used last, even while the pill is hidden; the arrow keys, Home and End move between its actions. The label names the element: “Equation 2.14”. element-pill.js, loaded once on the page, does this. Without it, every action is its own tab stop.
The actions
Plain <button> or <a> elements, with no class of their own. The pill gives each its small type, muted colour, a wash on hover and a 24px target floor. .is-cta marks the one main action in Link Blue.

The close control

Dismissing something is a simple job, but it needs a clear and consistent control everywhere it appears. Wether in an alert, a popover, an announcement banner, or an expanded figure, .ds-close supplies the right style.

Note

Close vs Dismiss: Use Close for something the reader opened, or when there is not space for a dismiss button. Use Dismiss for something the site put in front of the user.

On the page
On an alert
On dark chrome
Relevant code
.ds-close
The whole control. 32×32, quiet tier — no fill, no border, no shadow. It takes color: inherit, so one rule serves all four alert palettes, the pale announcement band and dark chrome without knowing which it is on. It sets no position.
.is-sr-only
Required. The icon is aria-hidden under the icon policy, so without this span the control announces as “button” and nothing more.
<button type="button" class="ds-close">
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
    <path d="M18 6 6 18"/>
    <path d="m6 6 12 12"/>
  </svg>
  <span class="is-sr-only">Dismiss announcement</span>
</button>

Accessibility essentials

Modifiers

Icon-only buttons

A button whose whole label is an icon. .ds-btn-icon modifies the shape of a primary, secondary, or text-only button.

Public
Internal
Disabled
Destructive
Relevant code
.ds-btn-text.ds-btn-destructive
The quiet destructive: the text tier in the danger colour, for a remove action in a table row or a toolbar where a filled red on every row would be alarm rather than information. Works with a label as well as with an icon.
.ds-btn-icon
The shape. Square by aspect-ratio, min-width: 0, equal padding, no label gap. Always used with a tier — .ds-btn .ds-btn-text .ds-btn-icon, never .ds-btn-icon alone.
.is-sr-only
Required. The icon is aria-hidden under the icon policy, so without this span the control announces as “button” and nothing more. Carbon and Primer both make this name a required prop; the systems that leave it optional are the ones with the known gap here. Prefer it to aria-label, which does not survive page translation.

On dark surfaces

The primary button works everywhere. The gradient border and vignette keep the edge legible on cool, warm, and dark backgrounds. The secondary button can be adapted with a modifier class when using it on a tinted background.

Cool tint (modify with .on-tint)

Warm tint (no modifier needed)

Dark tint (modify with .on-dark)

Relevant code
.on-tint
On a cool tint, swaps the secondary's white fill for Warm Tint (same luminance, warm hue) so it reads as secondary by material rather than by contrast. On a warm tint the default white secondary already sits comfortably.
.on-dark
For a field dark enough to host white text: an outreach masthead, a photo band. A white fill would read as a paper rectangle stuck to the surface, louder than the primary beside it; .on-dark drops the fill so the field shows through and draws the boundary with a white border. See outreach sites for where such fields are allowed.
Not this
A default white secondary on a cool tint pops too hard and reads as primary — that is the case .on-tint exists for. Do not put .on-tint on a warm tint: its Warm Tint fill melts into the surface. And .on-dark is only correct on a dark field; on a light tint use .on-tint.
<!-- Secondary on a cool tint, and on a committed color field -->
<a class="ds-btn on-tint" href="/issues">Submit a fix</a>
<a class="ds-btn on-dark" href="/subscribe">Subscribe</a>

Compact buttons

A smaller button for a small form, such as a single field with its own actions. .ds-btn-compact reduces the padding of a primary, secondary, text-only or icon-only button; its colour still comes from the surface.

Public
Internal

In a small form

Relevant code
.ds-btn-compact
Sets smaller padding and a smaller minimum width on the button. It works with every tier and with .ds-btn-icon.
When to use it
A small form, or a row of controls that sits inside content, where a full-size button would outweigh what it acts on. The main action of a page or of a full form stays full size.
<div class="ds-btn-group ds-btn-group--end">
  <button class="ds-btn ds-btn-text ds-btn-compact" type="button">Cancel</button>
  <button class="ds-btn ds-btn-primary ds-btn-compact" type="submit">Rename</button>
</div>

Button groups

A set of related buttons with a parent container class that spaces them appropriately.

Side by side

Relevant code
.ds-btn-group
The container. Flex, wrapping, vertically centred, gap --ds-space-tight. Nothing about buttons makes their spacing special: two side by side are siblings that belong together, so they take the same gap as any other such pair.

Stacked — .ds-btn-group--stack

Relevant code
.ds-btn-group--stack
The same relationship on the other axis. Items align to the start rather than stretching.

A form’s action area — .ds-btn-group--end

Relevant code
.ds-btn-group--end
Pushes the group to the trailing edge. This is the action area at the end of a form, where the primary action comes last.

One choice at each end — .ds-btn-group--split

Relevant code
.ds-btn-group--split
One choice at each end, for a pair that goes opposite ways — Back against Continue in a stepped form.

Only use for pairs. Three buttons split like this leaves the middle one belonging to neither side.

A group of toggles

Buttons that each turn on one choice, such as a sort bar: the buttons join into one bar, and the choice that is on is tinted. Each press applies at once. Use a sort bar for up to five ways to sort a list or a set of rows that are not a table; use a sortable column header in a table, and a Sort by select in a search form.

A sort bar

Sort charts by
Relevant code
<form method="get" action="buttons.html#a-group-of-toggles">
  <div class="ds-btn-group" role="group" aria-labelledby="sort-by">
    <span id="sort-by">Sort charts by</span>
    <input type="hidden" name="group" value="cs">
    <button class="ds-btn sort-asc" type="submit" name="sort" value="category-desc" aria-pressed="true">Category <span class="sort-arrow">↑</span><span class="is-sr-only">, A to Z</span></button>
    <button class="ds-btn" type="submit" name="sort" value="holds" aria-pressed="false">Current holds <span class="sort-arrow">↕</span></button>
    <button class="ds-btn" type="submit" name="sort" value="weekly" aria-pressed="false">Weekly holds trend <span class="sort-arrow">↕</span></button>
    <button class="ds-btn" type="submit" name="sort" value="monthly" aria-pressed="false">Monthly holds trend <span class="sort-arrow">↕</span></button>
  </div>
</form>
.ds-btn-group with role="group"
The bar, named by its label through aria-labelledby. When its buttons have aria-pressed, they join, and the bar is compact. Here the bar sits in a GET form, so it works without JavaScript; hidden inputs keep the reader's other choices in the address. The group role goes on the bar, not on the form.
type="submit" with name and value
Each button sends its sort. The button that is on sends the reverse direction, so pressing it again reverses the order.
aria-pressed
On every button: "true" on the one that is on, "false" on the rest. Off is plain; on takes the accent tint.
.sort-asc, .sort-desc, .sort-arrow
For a sort, the arrow shows the direction on the button that is on, as in a sortable column header. Pressing it again reverses the direction. An .is-sr-only span says the direction in words.

A sort bar with another control

Sort by
Relevant code
<div class="ds-btn-group ds-btn-group--split">
  <form method="get" action="buttons.html#a-group-of-toggles">
    <div class="ds-btn-group" role="group" aria-labelledby="sort-by-2">
      <span id="sort-by-2">Sort by</span>
      <button class="ds-btn sort-desc" type="submit" name="sort" value="holds-asc" aria-pressed="true">Current holds <span class="sort-arrow">↓</span><span class="is-sr-only">, largest first</span></button>
      <button class="ds-btn" type="submit" name="sort" value="category" aria-pressed="false">Category <span class="sort-arrow">↕</span></button>
    </div>
  </form>
  <button class="ds-btn ds-btn-text" type="button">Categories (40)</button>
</div>
.ds-btn-group--split
Two groups of controls for one list, on one row: the sort bar at the left edge, the other control at the right edge.