Skip to content

Conversation

@abhishekxix
Copy link
Member

@abhishekxix abhishekxix commented Jan 7, 2026

Description

This PR migrates the component library from radix-ui to base-ui.

Components Migrated:
Dialog - Migrated from @radix-ui/react-dialog to @base-ui/react/dialog
Dropdown - Migrated from @radix-ui/react-dropdown-menu to @base-ui/react/menu
Toast - Migrated from @radix-ui/react-toast to @base-ui/react/toast
Tooltip - Migrated from @radix-ui/react-tooltip to @base-ui/react/tooltip

Relevant Technical Choices

Key Changes:

  • Replaced all Radix UI primitives with their Base UI equivalents
  • Updated animation data attributes from data-state="open/closed" to data-open/data-closed
  • Refactored Toast system to use Base UI's toast manager pattern with createToastManager() and useToastManager()
  • Updated Dialog overlay naming from dialog-overlay to dialog-backdrop to align with Base UI conventions
  • Adjusted component APIs to use Base UI's render prop pattern instead of Radix's asChild
  • Updated Tooltip arrow positioning with explicit CSS transforms for each side

Testing Instructions

Dialog

  1. Open Storybook: npm run storybook
  2. Navigate to Components/Dialog
  3. Verify:
    • Dialog opens and closes with animations
    • Click outside to close works (when disableOutsideClickToClose is false)
    • Escape key closes the dialog
    • All dialog sizes render correctly (xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl)
    • Action buttons function properly
    • Title and message content displays correctly

Dropdown

  1. Navigate to Components/Dropdown in Storybook
  2. Verify:
    • Dropdown opens on trigger click
    • Menu items are clickable and fire onClick handlers
    • Submenus open correctly on hover/click
    • Switch items toggle without closing the dropdown
    • Group labels display properly
    • Placement options (left, right) position correctly

Toast

  1. Navigate to Components/Toast in Storybook
  2. Verify:
    • Toasts appear with slide-up animation
    • Different toast types show correct icons (success, warning, error, info)
    • Toasts auto-dismiss after duration
    • Close button dismisses toast immediately
    • Swipe down gesture dismisses toast
    • Action buttons are clickable
    • toast.promise() shows loading → success/error states correctly
    • Non-closable toasts (closable: false) don't show close button and don't auto-dismiss

Tooltip

  1. Navigate to Components/Tooltip in Storybook
  2. Verify:
    • Tooltip appears on hover after delay
    • All placement options work (top, bottom, left, right)
    • Arrow points correctly for each placement
    • Text and custom content tooltips render properly

Additional Information:

Breaking Changes:

  • Toast ToastProps interface has changed - now accepts a toast object from the toast manager instead of individual props
  • Internal toast data structure uses ToastDataInternal for custom properties like icon and closable

Screenshot/Screencast

N/A - This is a dependency migration with no visual changes expected. Components should look and behave identically to before.


Checklist

  • I have thoroughly tested this code to the best of my abilities.
  • I have reviewed the code myself before requesting a review.
  • This code is covered by unit tests to verify that it works as intended.
  • The QA of this PR is done by a member of the QA team (to be checked by QA).

See #108

@abhishekxix abhishekxix self-assigned this Jan 7, 2026
@abhishekxix abhishekxix changed the title Chore/migrate to base UI Chore: Migrate from radix-ui to base-ui Jan 7, 2026
@abhishekxix abhishekxix marked this pull request as ready for review January 9, 2026 11:40
Copilot AI review requested due to automatic review settings January 9, 2026 11:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the component library from Radix UI to Base UI, replacing four key components: Dialog, Dropdown, Toast, and Tooltip. The migration introduces breaking changes to the Toast API and updates component implementations to use Base UI's render prop pattern instead of Radix's asChild approach.

Key Changes:

  • Replaced all Radix UI primitives with Base UI equivalents across four components
  • Migrated Toast system to use Base UI's toast manager pattern with createToastManager() and useToastManager()
  • Updated animation data attributes from data-state="open/closed" to data-open/data-closed throughout CSS

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/frappe-ui-react/package.json Removed 4 @radix-ui packages and added @base-ui/react dependency
package-lock.json Updated lockfile with base-ui dependencies and version bump to 1.0.2
packages/frappe-ui-react/src/components/tooltip/tooltip.tsx Migrated to Base UI Tooltip with render props and custom arrow positioning
packages/frappe-ui-react/src/components/tooltip/tooltip.stories.tsx Added placement prop to story example
packages/frappe-ui-react/src/components/toast/types.ts Restructured Toast types to work with Base UI's ToastObject and toast manager
packages/frappe-ui-react/src/components/toast/toastProvider.tsx Implemented Base UI toast manager with createToastManager and useToastManager hooks
packages/frappe-ui-react/src/components/toast/toast.tsx Refactored to use Base UI Toast primitives with new animation system
packages/frappe-ui-react/src/components/toast/toast.stories.tsx Fixed whitespace formatting (tabs to spaces)
packages/frappe-ui-react/src/components/dropdown/dropdown.tsx Migrated to Base UI Menu with render props and updated submenu structure
packages/frappe-ui-react/src/components/dialog/types.ts Changed title type from ReactNode to ReactElement for stricter typing
packages/frappe-ui-react/src/components/dialog/dialog.tsx Migrated to Base UI Dialog with Backdrop, Viewport, and Popup components
packages/frappe-ui-react/src/components/dialog/dialog.css Updated animation selectors from data-state to data-open/data-closed attributes

@b1ink0 b1ink0 linked an issue Jan 9, 2026 that may be closed by this pull request
@b1ink0 b1ink0 changed the base branch from main to develop January 9, 2026 13:36
@abhishekxix abhishekxix requested a review from b1ink0 January 12, 2026 07:55
@abhishekxix abhishekxix requested a review from b1ink0 January 12, 2026 11:33
Copy link
Collaborator

@b1ink0 b1ink0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

return toastManager.add<ToastDataInternal>({
id: options?.id || id,
timeout: durationInMs,
description: sanitizedMessage,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be description: <span dangerouslySetInnerHTML={{ __html: sanitizedMessage }} /> ?

We are using DOMPurify.sanitize for sanitizedMessage, which means sanitizedMessage message supports HTML tags.

I think with the current implementation, this will render as:
This is <b>Bold</b> and this is <i>Italic</i> (The tags are visible as text) (existing issue)

for example if you try creating a test story with this component, you may be able see the issue.

export const HTMLUsage = () => {
  const toast = useToasts();

  const triggerToast = () => {
    toast.info("This is <b>Bold</b> and this is <i>Italic</i>");
  };

  return (
    <div className="flex flex-col gap-4 p-8">
      <Button onClick={triggerToast}>Trigger HTML Toast</Button>
    </div>
  );
};

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right @mohdsayed. I have added the fix.

@mohdsayed
Copy link
Member

@abhishekxix Let's add test coverage for these components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate to Base UI

4 participants