Pill
A lozenge that floats an in-progress status over the page. Use it for information that keeps updating: a recording timer, a build still running.
import { Pill } from 'neba';
<Pill startIcon={<DotIcon />} color="danger" title="Recording" />;Props
| Prop | Type | Default | Description |
|---|---|---|---|
| variantshared | 'solid' | 'outline' | 'text' | 'solid' | Weight of the surface, said the way a *control* says it: the surface takes the tint, as on Button and Chip |
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Height and type scale |
| colorshared | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'secondary' | Semantic colour role. `secondary` here rather than `primary`, because the object this shape is borrowed from is very nearly neutral black |
| densityshared | 'default' | 'compact' | 'default' | Padding only: never the height, never the type scale |
| elevationshared | 0 | 1 | 2 | 3 | 2 | Drop shadow depth. `2` against the `0` everything else defaults to, and not an inconsistency: a Pill is defined by not being part of the page, and a lozenge floating flat on the content it floats over reads as a mistake |
| startIcon | ReactNode | — | The leading slot: a glyph, an avatar, a status dot, a photo. It is given a square box of its own and clipped to a circle, so an `<img>` lands in it as readily as an icon does |
| title | ReactNode | — | The headline in the middle: what the pill is currently about. Centred, with generous room either side of it |
| description | ReactNode | — | The second line, under the title. One step down and one step lighter |
| endIcon | ReactNode | — | The trailing slot. Outside the pressable area, so it can be a control of its own |
| details | ReactNode | — | The second half, revealed when `expanded`. The pill grows downward into it rather than swapping to a different shape: one object saying more, which is the whole idea being borrowed |
| expanded | boolean | false | Whether `details` is showing |
| positionshared | 'static' | 'sticky' | 'fixed' | 'static' | How it sits in the page’s scroll. `fixed` pins it against the viewport and centres it horizontally, which is the arrangement this shape exists for |
| sideshared | 'top' | 'bottom' | 'top' | Which edge it is held against when `position` is not `static` |
| onClick | MouseEventHandler | — | Passing it makes the row a real button. `endIcon` stays outside it: a `<button>` inside a `<button>` is markup the browser rewrites on parse |
| children | ReactNode | — | The middle: a line of text, a pair of small readouts |
Every native <div> attribute passes through except title, which here is the pill's headline rather than the browser's tooltip.
The row has three parts: startIcon on the leading edge, endIcon on the trailing one, and the middle (title, description and anything in children) centred between them with generous padding either side.
color defaults to secondary and elevation to 2: it is meant to float, so the shadow is on by default.
Examples
title and description
title is the line the pill is about and description is the line under it. Both are optional: a title on its own keeps the row one line tall and the shape a true stadium, and adding a description grows it into a rounded rectangle with the same corner.
startIcon and endIcon
The leading slot is a square box clipped to a circle, so an <img> fills and crops it the way an avatar should. The trailing slot sits outside the pressable area, so it can hold a readout or a control of its own.
details and expanded
details grows a second area beneath the pill. expanded makes that controlled, and onClick attaches the toggle. It expands by animating its height, the same way an Accordion panel does.
The details area is inert while closed. Focus can still enter a zero-height element, so aria-hidden alone would leave a keyboard user tabbing into something invisible.
variant and size
As far as colour goes a Pill is a control rather than a container: like a Button or a Chip, the surface itself takes the colour.
position and side
The same vocabulary Toolbar uses. fixed pins it against the viewport and centres it horizontally with auto margins, so it stays centred under RTL.
<Pill
position="fixed"
side="top"
startIcon={<BuildIcon />}
color="info"
title="Building — 2 of 7"
/>