Enhanced Add-Ons, Round Two
Round two. Since January's batch of extra components, four more Enhanced Add-Ons have landed: original components that go past what the Bulma spec covers while keeping Bulma's helper props, CSS variables, and theming. Meet Avatar (and its stacking sibling Avatars), Badge, Reveal, and LinkButton.
New since January
Same housekeeping as the v3 forms recap: this is a recap, not breaking news. Reveal landed in 5.3.0 on July 8, Avatar, Avatars, and Badge followed in 5.4.0 two days later, and the library sits at 5.8.0 today. And a confession about LinkButton: it isn't new at all. It shipped in the very same commit as the components the January post announced, and that post just never mentioned it. If a component ships in a release and no blog post names it, did it even ship? Consider this its overdue introduction. We won't re-explain the first eight here; the January post has them covered.
Avatar & Avatars
Avatar shows a person as a photo, initials, or an icon, whichever is available. Avatars stacks them with an overlap and a surplus bubble.
- Automatic fallback chain: photo, then initials, then icon, plus shapes and sizes from 16 to 128 pixels (or any number you want)
- Clickable avatars render a real link or button, and
imagePropsreaches the underlyingimg Avatarsclamps a long list behind a surplus bubble, takes a localized surplus label, and has a spaced, non-overlapping mode
All three fallback stages, side by side. The first loads a real photo, the second points at a domain that's guaranteed to fail (so it falls back to initials), and the third has no photo or name at all:
<Avatars spaced> <Avatar src="https://github.com/allxsmith.png" name="Al Smith" size="64x64" /> <Avatar src="https://example.invalid/missing.jpg" name="Grace Hopper" size="64x64" /> <Avatar icon={<Icon name="user" />} color="info" size="64x64" /> </Avatars>
There's a fourth stage too: with no photo, name, or icon, a built-in generic silhouette renders. And the initials background isn't random. It's hashed deterministically from the name, so Grace gets the same color on every page load.
Badge
Badge overlays a count or status dot on the corner of anything, or stands alone as a pill.
- Counts with a max (past it the pill shows a plus), dots, and custom node content
- Four positions and an overlap mode that hugs round targets correctly
- Pulse for in-progress states (it goes still under reduced motion), visibility toggling, and zero handling with
showZero - Standalone mode when there's nothing to overlay
A cart button that counts, with a max:
function CartDemo() { const [items, setItems] = React.useState(2); return ( <Block display="flex" alignItems="center"> <Badge content={items} max={9} color="danger" overlap="square" mr="5"> <Button color="primary"> <Icon name="shopping-cart" ariaLabel="Cart" /> <span>Cart</span> </Button> </Badge> <Button onClick={() => setItems(count => count + 1)}>Add item</Button> </Block> ); }
Click past nine and the pill reads 9+. The count lives in a polite live region, which matters more than it sounds (more on that below).
Reveal
Reveal animates content into view as it scrolls into the viewport, with IntersectionObserver doing the watching and zero animation libraries in your bundle.
- Seven animation styles with
delay,duration, andthresholdknobs - Cascade staggers children, and
once={false}re-animates on every entry - Polymorphic
asrenders the observed element as any tag
Three boxes, one Reveal, staggered 120 milliseconds apart:
<Reveal animation="fade-up" cascade cascadeInterval={120} display="flex" flexWrap="wrap" > <Box m="2" flexGrow="1"> <Title size="5">First</Title> <Content>Each direct child gets its own delay.</Content> </Box> <Box m="2" flexGrow="1"> <Title size="5">Second</Title> <Content>120 milliseconds behind the one before it.</Content> </Box> <Box m="2" flexGrow="1"> <Title size="5">Third</Title> <Content>No animation runtime in your bundle.</Content> </Box> </Reveal>
Two things worth knowing. First, cascade staggers only the direct children of Reveal, so hand it the items themselves, not a wrapper component. Second, and this one matters: Reveal respects prefers-reduced-motion. When the reader's OS asks for less motion, the animation is skipped entirely and content simply appears. It also renders everything visible during SSR, so crawlers and no-JS visitors never get a blank page. The full accessibility story is on the API page.
LinkButton
The component the January post forgot. LinkButton is a real <button> dressed as text or a link, and it exists to kill the <div onClick> pattern: you keep native keyboard focus, Enter and Space handling, and screen reader semantics while looking like prose.
- Three variants, text, ghost, and underline, in any Bulma color and size
- Polymorphic
asfor router links - Everything
Buttonoffers passes through, minus the three props that make no sense on a link look (isOutlined,isInverted,isLight)
<Buttons> <LinkButton>Text variant</LinkButton> <LinkButton variant="ghost">Ghost variant</LinkButton> <LinkButton variant="underline" color="primary"> Underline variant </LinkButton> </Buttons>
Built for Accessibility
Some honesty about the rollout: Avatar and Badge shipped in 5.4.0 on a Friday, and by the following Tuesday we'd landed 5.4.1, 5.4.2, and a dedicated 5.5.0 accessibility batch. Shipping fast and patching fast are the same muscle, and the result is a set of defaults we're happy to stand behind:
- An avatar with an explicit
alt=""is treated as decorative and skipped by screen readers entirely, but never when it's a link or a button - Link and button avatars always get an accessible name, even when you forget to provide one
- Badge's
role="status"live region stays mounted even when a zero hides the pill, so a change from 0 to 1 is announced reliably instead of inserting a region nobody hears - Keyboard focus on a stacked avatar lifts it above its overlapping neighbors, so the focus ring is never buried
- The surplus label in
Avatarsis localizable, andas="button"avatars default totype="button"so a click can't accidentally submit a form
Reveal didn't need the patch batch. Its accessibility story shipped on day one: content never leaves the accessibility tree, the animation touches only opacity and transform, and reduced motion turns it off.
Themeable like Stock Bulma
Every Enhanced Add-On follows the same SCSS contract as the stock components: its variables derive from Bulma tokens (never hardcoded hex) and register as --bulma-* CSS variables on the component root. That's why the Theme component and plain CSS overrides work on the extras exactly like they work on a Button.
Take the badge's ring, the thin outline separating the pill from whatever sits behind it. It defaults to var(--bulma-scheme-main), the page's scheme color, so it's already correct in dark mode without a dark-mode rule anywhere. Want it branded? One variable:
.badge {
--bulma-badge-ring-color: var(--bulma-primary);
}
The same goes for the rest: avatar size, background, and radius; Reveal's duration and easing riding Bulma's own motion tokens. Initials avatars even pick their background from Bulma's palette (primary, link, info, success, warning, danger), so a retheme recolors your avatars with everything else. Each API page lists its variables at the bottom: Avatar, Badge, Reveal. For the bigger picture, see the Theme helper and the CSS variables guide.
All 12 Enhanced Add-Ons
The full set, straight from the homepage grid, four of them new since January:
| Component | What it does |
|---|---|
| LinkButton | A button that dresses like a link: semantics of a button, look of an anchor. |
| Avatar | User images with automatic initials and icon fallbacks, in any size or shape. |
| Badge | Corner status dots and counts overlaid on any element. |
| Carousel | Slide any content with autoplay, drag, arrows, and indicators. |
| Collapse | Smoothly expanding panels for accordions and FAQs. |
| Dialog | Confirmation and alert dialogs with customizable actions. |
| Loading | Spinner overlays for full pages or single containers. |
| Reveal | Scroll-triggered entrance animations, solo or cascading, that respect reduced motion. |
| Sidebar | Slide-out navigation panels from either edge. |
| Steps | Multi-step progress for wizards and checkouts. |
| Toast | Brief stacking notifications with a programmatic API. |
| Tooltip | Hover hints in any direction and color. |
Documentation
- API references: Avatar, Avatars, Badge, Reveal, and LinkButton
- Theming: the Theme helper and the CSS variables guide
- Round one: Introducing Extra Components, the first eight
