Skip to content

BbSmoothHeight

Animates its own height whenever the content it wraps changes size.

import { BbSmoothHeight } from 'bitboss-ui';

On this page

Use it for

Wrap a region whose height moves on its own: a panel that grows when data lands, a validation message under a field, a list gaining rows. It has no model, no trigger and no events.

Use something else when

Pass Through

Hover or tap a part to outline it. Toggles flip loading, errors and warnings when the component has them — only parts highlight.

This component hides nothing. Whatever you put inside stays mounted, focusable and announced to screen readers even at near-zero height. If a region has to genuinely disappear, you want one of the other two.

Wrap what changes height

Put the component around the region that moves. There is nothing else to pass.

Aeris Ergonomic Task Chair

FUR-CHR-1042 · Furniture

While it animates, the wrapper carries a fixed inline height. Do not stretch it from outside with height: 100%, and do not read its height mid-animation.

It clips vertically only, so shadows, focus rings and popovers still escape sideways.

Measuring starts on mount. A server-rendered page carries the content at its natural height and reads correctly without JavaScript.

Swapping one block for another

The same wrapper handles replacement, not just reveal.

Delivery

A v-if/v-else that swaps two blocks of different height glides instead of snapping. That covers a wizard step, or a form section that depends on an earlier choice.

Wrap only the region that actually swaps. The controls above it and the actions below stay put, which is what makes the movement readable.

An async panel is the same case with three branches: spinner, results, empty state. Keep all three inside one wrapper.

Lists that gain and lose rows

Stay on resize, the default: it sees anything that changes the measured box.

Recent orders

  • ORD-2026-0417Delivered
  • ORD-2026-0418Delivered

Switch to strategy="mutation" when you want to react only to nodes being added and removed. The default watch scope is { childList: true }: direct children only. Widen it with mutation-options, a standard MutationObserverInit. subtree: true catches nested inserts, and attributes or characterData cover class swaps and text edits.

resize-options is the counterpart on the default path and forwards ResizeObserverOptions. Changing the strategy, the options, disabled or transition-duration at runtime rewires the observer on its own.

The element and the timing

tag picks the element: div by default, or span where the surrounding markup only accepts phrasing content.

Shipping to Milan. Delivery in 2–3 working days.

Both are forced to display: block, so a span measures and animates exactly like a div. The choice is only about what the surrounding markup accepts.

transition-duration is the length in milliseconds, 250 by default; the easing comes from the --bb-ease token. disabled opts out entirely, and it is reactive, so flip it per instance when a parent already animates height.

You do not need disabled for reduced motion. Under prefers-reduced-motion: reduce the transition collapses in CSS, so the height still updates and the layout stays correct.

Coming from v2tag takes only div and span

In v3 the list is exactly those two, and the inner measuring element mirrors the tag instead of always being a <div>. If you passed tag="section" or tag="ul", wrap that element around BbSmoothHeight instead.

When not to use it

Every animated frame re-runs layout for everything inside. That is nothing for a card. In four cases it is a real problem:

  • Continuously resizing content: a textarea being typed into, streaming output, anything animating inside. The transition never stops.
  • Large or expensive subtrees: a virtualized table, a long feed. Wrap a small container near the change instead, and keep subtree: true off a big tree.
  • Inside BbCollapsible or BbAccordion: they already animate height, and a second animation inside gives you double easing.
  • When the content must genuinely disappear: here it stays focusable and still announced. Use a collapsible.