CSS
A native <button> with two children: the decorative ai-sparkle glyph and a label. At rest the label column is collapsed to zero width (the button is a circle); on :hover, :focus-visible, and :active it expands to reveal the label. This is pure CSS — no JavaScript, and the label stays in the DOM so it is the button’s accessible name.
<button class="tng-ai-button" type="button"> <i class="tng-icon icon-ai-sparkle" aria-hidden="true"></i> <span>Hi, I'm Concierge</span></button>Elements
Section titled “Elements”The label is any non-icon child — no class needed (it is targeted structurally). It must be a real element (not a bare text node) because it is the grid column that collapses and clips at rest. Keep it short: the button expands to the label’s content width.
The glyph is decorative — mark it aria-hidden="true". The button takes its accessible name from the label text, so the icon never needs its own.
Behaviour
Section titled “Behaviour”The expand / collapse is driven entirely by :hover, :focus-visible, and :active — there is no state class and no script. Keyboard focus expands the button as well, so keyboard and pointer users both reach the label. Width animates via a grid-column transition, the corner morphs (circle → the brand’s expanded shape), and the glyph steps from 40 px down to 20 px.
States
Section titled “States”Hover, focus, and active are driven by the browser and styled by the design system — no extra classes. Disabled uses the native disabled attribute; a disabled AI button does not expand.
<button class="tng-ai-button" type="button"> <i class="tng-icon icon-ai-sparkle" aria-hidden="true"></i> <span>Hi, I'm Concierge</span></button><button class="tng-ai-button" type="button" disabled> <i class="tng-icon icon-ai-sparkle" aria-hidden="true"></i> <span>Hi, I'm Concierge</span></button>