No.80 · Buttons· New
Bunting
Point at the button and a string of pennants drops over it, sagging between two pins and swinging as it settles. Move the pointer and the flags nearest it catch the gust; press and they all flutter. Leave and the string lifts away. Fête colours, nautical stripes or black and white.
The prompt
Written for the variant you picked above: Fête
Build a pill button that bunting is hung over. Props: children, look (one of three flag sets), onClick, type and motion. Helpers (pure functions): flags every 19px along a line from just outside the button's left end to just outside its right end, 40px above its top, sagging 12px in the middle on a parabola — each with its position and the line's slope there in degrees; the line as one quadratic path; and a damped pendulum step for a flag's swing (stiffness 60, damping 3.2, plus a force). An SVG overlay above the button (58px tall, 16px wider each side, pointer-events none) holds two pins, the string and the pennants — 14px-wide triangles 17px long with a hairline edge and a soft shadow, some with a trim stripe — each hanging from the string at its point and turned to its slope plus its swing. On pointerenter the whole string drops in with a springy overshoot (620ms) and the flags unfold from the top one after another (32ms apart); they land swinging alternately ±14°. Moving the pointer sideways gusts them: a force from the pointer's horizontal speed, strongest at the flag nearest the pointer and falling off over 70px. Pressing makes them all flutter on a fast sine that dies away. Swings run on requestAnimationFrame only while something moves, setting each flag's transform directly. On leave the string lifts away and fades. Keyboard focus hangs it; touch hangs it on press for 2.6s. Reduced motion only fades it in and out. The button: a 54px pill with a light label and a 1px lift on hover. Leave room above it for the bunting. Selected variant — Fête (fete): Coral #ff5d73, sunflower #ffc23d, green #2bb98a and blue #4a8cff pennants on a brown string over a deep violet #2b2140 button, on cream #fff4e3. This selection takes precedence over references to other themes or options in the general brief. Implement this selected appearance; do not add a variant picker or alternative appearances unless requested. Implementation requirements: Use React and TypeScript. Keep the component self-contained, with uniquely scoped CSS and no animation libraries. Include required imports, styles and font setup in the result. Interaction: Point at the button to hang the bunting; move along it to blow the flags; press to make them flutter; leave to take it down. Motion: The string drops in 620ms with an overshoot, flags unfold 32ms apart and swing on damped springs; leaving lifts it in 420ms. Reduced motion only fades. Accessibility: A real button with its text label; the bunting is decorative SVG, hidden and pointer-transparent. Responsive behavior: The string spans whatever width the button has; leave about 58px of room above it. Touch: A press hangs the bunting and makes it flutter for a couple of seconds. Preserve keyboard access, visible focus and reduced-motion behavior. Keep fictional demo data and simulated service calls in a separate usage example; expose callbacks for real actions and recover from rejected requests. Keep usage-example links inside the demo: use local buttons or prevent navigation. Demonstration links must not navigate to Vitrine routes or open other pages; preserve real URL support in the reusable component itself. Verify the result at narrow and wide viewport sizes, with keyboard input and reduced motion enabled.
Notes
- Interaction
- Point at the button to hang the bunting; move along it to blow the flags; press to make them flutter; leave to take it down.
- Motion
- The string drops in 620ms with an overshoot, flags unfold 32ms apart and swing on damped springs; leaving lifts it in 420ms. Reduced motion only fades.
- Accessibility
- A real button with its text label; the bunting is decorative SVG, hidden and pointer-transparent.
- Responsive
- The string spans whatever width the button has; leave about 58px of room above it.
- On touch
- A press hangs the bunting and makes it flutter for a couple of seconds.