Button in src/ui/button.tsx is a plain function component:
export function Button({ className, variant, size, asChild = false, ...props }: ButtonProps) {
const Comp = asChild ? Slot : "button";
return <Comp data-slot="button" className={cn(buttonVariants({ variant, size }), className)} {...props} />;
}
It is not wrapped in React.forwardRef, so a consumer passing ref gets no DOM node and no compile-time warning — the ref silently does nothing.
Motivating case: workbench's stage-search.tsx needs ref={buttonRef} to restore keyboard focus to the trigger button after its command palette closes. During a recent pass converting workbench's raw controls to react-ui primitives (corbitsdev/workbench#217), this site had to stay on a raw <button> specifically because swapping to Button would have silently broken that focus restoration.
Ask: wrap Button in React.forwardRef<HTMLButtonElement, ButtonProps> (mirroring how ref-forwarding is presumably already handled for any other interactive primitives in this library), so ref works whether asChild is set or not.
Buttoninsrc/ui/button.tsxis a plain function component:It is not wrapped in
React.forwardRef, so a consumer passingrefgets no DOM node and no compile-time warning — the ref silently does nothing.Motivating case: workbench's
stage-search.tsxneedsref={buttonRef}to restore keyboard focus to the trigger button after its command palette closes. During a recent pass converting workbench's raw controls to react-ui primitives (corbitsdev/workbench#217), this site had to stay on a raw<button>specifically because swapping toButtonwould have silently broken that focus restoration.Ask: wrap
ButtoninReact.forwardRef<HTMLButtonElement, ButtonProps>(mirroring how ref-forwarding is presumably already handled for any other interactive primitives in this library), sorefworks whetherasChildis set or not.