Appearance

A design for the whole site, in light or dark. Kept on this device.

Design
Mode

Box Kite 2.2.18

3 November 2026
What changed in this version, written as it landed. The same notes are the body of the GitHub release.

3 November 2026 · npm · Compare v2.2.17...v2.2.18

A prop you pass now beats a component's own styles when it is a shorthand too, so <Button p={0}> has no padding — and toasts expire on time again, reach the reader from inside an open modal, and no longer blink when a queued one takes a closed one's place.

Breaking changes

None.

Fixes

  • A shorthand prop lost to a component's longhand. <Button p={0}> kept the button's own px and py, because the component's longhands were declared after the caller's shorthand. A shorthand you pass now replaces the component's longhands under it, at the level you set it: p covers px/py/pt…, and the same goes for m, b, borderRadius, inset, gap, overflow, gridColumn and gridRow, in every design and theme. A component's hover={{ px: … }} still applies on hover, the way hover:px-6 survives p-0 in tailwind-merge.
  • inset beat a side written next to it. <Box inset={0} top={2}> had top: 0, because top/right/bottom/left were declared before inset. A side now wins over inset, insetX and insetY on the same element.
  • Toasts stopped expiring after one was closed or hovered away. The clock pauses while the pointer is over the stack or focus is in it, and only a pointerout or a blur restarted it, neither of which a toast sends when it is removed from under the pointer or with focus inside. So pressing a toast's close button, or hovering a toast as it left, kept every later toast on screen whatever its duration. The stack now re-reads both from the page whenever it changes.
  • A toast fired from inside an open modal was under its backdrop. Everything outside an open modal Dialog is inert, so the toast was dimmed, a press on it landed on the dialog, its close button could not take focus and a screen reader never heard it. While a modal Dialog is open, <Toaster> now moves its stack inside it, shown after it, and back out when the dialog closes; Escape on a toast there dismisses the toast and leaves the dialog open.
  • Closing a toast made the stack blink when more were waiting. Past limit, the next toast came in the moment one was dismissed, while the closing one was still fading out, so the stack drew one toast too many and shifted up for the length of the exit, then jumped back. A closing toast now keeps its place until its exit has run, and the next one fades in where it was. A queued toast dismissed before it was ever shown is dropped without being drawn.
  • The toast's close button is softer. The cross is two filled bars with rounded ends on a round button. The old one was meant to be two 1px lines, but its unset border sides fell back to medium, so each stroke rendered 16px by 4px with square ends.
  • Escape dropped focus to the page when a panel's content was gated on open. With prefers-reduced-motion (or a panel styled with no exit transition), <Popover>, <Menu> and <DatePicker> unmounted the focused child before the browser looked for it, so focus landed on <body> instead of the trigger. A layer that holds focus as it closes now puts it back on whatever had focus when it opened, while the panel is still shown; a press outside still leaves focus where the press put it.
  • A gradient stop refused a colour added with Box.extend(). bgGradient={{ linear: 'r', colors: ['brand', 'brand/40'] }} was judged whole and wrote no gradient at all, while every other place a colour is written took the token. A stop now takes an extend() colour and its opacity form on bgGradient and maskImage, and typechecks wherever bgColor has been augmented with it.