feat: Update ShadCN (BLO-1279)#2913
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughChangesBase UI migration
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant EditorConsumer
participant ShadCNOverlay
participant BaseUIPrimitive
participant EditorPortal
EditorConsumer->>ShadCNOverlay: provide editor.portalElement
ShadCNOverlay->>BaseUIPrimitive: render portal and positioned popup
BaseUIPrimitive->>EditorPortal: mount overlay content
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
@blocknote/ariakit
@blocknote/code-block
@blocknote/core
@blocknote/mantine
@blocknote/react
@blocknote/server-util
@blocknote/shadcn
@blocknote/xl-ai
@blocknote/xl-docx-exporter
@blocknote/xl-email-exporter
@blocknote/xl-multi-column
@blocknote/xl-odt-exporter
@blocknote/xl-pdf-exporter
commit: |
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/shadcn/src/components/ui/button.tsx (1)
43-54: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy liftPreserve submit behavior for in-form
<Button>usage.Base UI
Buttondefaults totype="button", so any<ShadCNComponents.Button.Button>inside a form that relied on the native omittedtypewill no longer submit. Add explicittype="submit"where this is intended.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/shadcn/src/components/ui/button.tsx` around lines 43 - 54, Update the Button component’s ButtonPrimitive props to explicitly set type="submit", preserving submit behavior for form usage while retaining the existing variant, size, className, and forwarded props handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/shadcn/src/components/ui/tabs.tsx`:
- Around line 8-24: Update the Tabs wrapper to explicitly pass the resolved
orientation value to TabsPrimitive.Root after destructuring it, while preserving
the existing data-orientation styling and other props. This ensures Base UI
receives "vertical" when requested instead of falling back to horizontal
behavior.
In `@packages/shadcn/src/toolbar/Toolbar.tsx`:
- Around line 91-101: The Toggle styling in the toolbar targets aria-expanded
instead of the Toggle’s pressed state. Update the className in the Toggle.Toggle
usage to use the established pressed-state selector, preferably data-[pressed]
for Base UI Toggle, while preserving the existing accent highlight styles and
compact variant classes.
---
Outside diff comments:
In `@packages/shadcn/src/components/ui/button.tsx`:
- Around line 43-54: Update the Button component’s ButtonPrimitive props to
explicitly set type="submit", preserving submit behavior for form usage while
retaining the existing variant, size, className, and forwarded props handling.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 6432d81f-557c-4958-ac8d-daf87dbd2bbd
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (24)
packages/shadcn/components.jsonpackages/shadcn/package.jsonpackages/shadcn/src/ShadCNComponentsContext.tsxpackages/shadcn/src/badge/Badge.tsxpackages/shadcn/src/components/ui/avatar.tsxpackages/shadcn/src/components/ui/badge.tsxpackages/shadcn/src/components/ui/button.tsxpackages/shadcn/src/components/ui/card.tsxpackages/shadcn/src/components/ui/dropdown-menu.tsxpackages/shadcn/src/components/ui/form.tsxpackages/shadcn/src/components/ui/input.tsxpackages/shadcn/src/components/ui/label.tsxpackages/shadcn/src/components/ui/popover.tsxpackages/shadcn/src/components/ui/select.tsxpackages/shadcn/src/components/ui/skeleton.tsxpackages/shadcn/src/components/ui/tabs.tsxpackages/shadcn/src/components/ui/toggle.tsxpackages/shadcn/src/components/ui/tooltip.tsxpackages/shadcn/src/menu/Menu.tsxpackages/shadcn/src/popover/popover.tsxpackages/shadcn/src/style.csspackages/shadcn/src/suggestionMenu/SuggestionMenu.tsxpackages/shadcn/src/suggestionMenu/gridSuggestionMenu/GridSuggestionMenu.tsxpackages/shadcn/src/toolbar/Toolbar.tsx
| function Tabs({ | ||
| className, | ||
| orientation = "horizontal", | ||
| ...props | ||
| }: React.ComponentProps<typeof TabsPrimitive.Root>) { | ||
| }: TabsPrimitive.Root.Props) { | ||
| return ( | ||
| <TabsPrimitive.Root | ||
| data-slot="tabs" | ||
| className={cn("flex flex-col gap-2", className)} | ||
| data-orientation={orientation} | ||
| className={cn( | ||
| "group/tabs flex gap-2 data-[orientation=horizontal]:flex-col", | ||
| className, | ||
| )} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate tabs.tsx and package files =="
fd -a 'tabs\.tsx$|package\.json$|pnpm-lock\.yaml$|package-lock\.json$|yarn\.lock$|bun\.lockb$' . | sed 's#^\./##' | head -200
echo
echo "== inspect packages/shadcn/src/components/ui/tabs.tsx =="
if [ -f packages/shadcn/src/components/ui/tabs.tsx ]; then
cat -n packages/shadcn/src/components/ui/tabs.tsx
fi
echo
echo "== search base-ui-tab dependencies/usages =="
rg -n '"`@base-ui/react`|`@base-ui/react/tabs`|TabsPrimitive|tabsPrimitive' -S . --glob '!node_modules' --glob '!dist' --glob '!build' | head -200Repository: TypeCellOS/BlockNote
Length of output: 16269
🌐 Web query:
Base UI React Tabs Root orientation prop default horizontal keyboard navigation aria-orientation
💡 Result:
In the Base UI React Tabs component, the orientation prop on the Tabs.Root component defaults to 'horizontal' [1][2][3][4]. Regarding keyboard navigation and aria-orientation: 1. Keyboard Navigation: The orientation prop determines the arrow key behavior for navigating between tabs [5][6]. When set to 'horizontal' (default), users navigate using the left and right arrow keys [5]. When set to 'vertical', navigation switches to the up and down arrow keys [5][6]. 2. aria-orientation: The Tabs.List component automatically applies the aria-orientation attribute based on the orientation prop [7]. Specifically, the code implements the following logic for the aria-orientation attribute [7]: - If orientation is 'vertical', aria-orientation is set to 'vertical' [7]. - If orientation is 'horizontal', aria-orientation is not set (undefined) [7]. This behavior aligns with standard accessibility practices where horizontal tab lists typically do not require the explicit aria-orientation attribute as it is the default behavior for screen readers [7].
Citations:
- 1: https://base-ui.com/react/components/tabs.md
- 2: https://base-ui.com/react/components/tabs
- 3: https://github.com/mui/base-ui/blob/d81ec002/packages/react/src/tabs/root/TabsRoot.tsx
- 4: https://mui-base-ui.mintlify.app/components/tabs
- 5: https://github.com/mui/base-ui/blob/d81ec002/packages/react/src/tabs/root/TabsRoot.test.tsx
- 6: https://v6.mui.com/base-ui/react-tabs/
- 7: https://github.com/mui/base-ui/blob/d81ec002/packages/react/src/tabs/list/TabsList.tsx
🌐 Web query:
"orientation=" "Base UI React Tabs Root" documentation
💡 Result:
The Tabs component in Base UI is a headless, unstyled React component used for organizing and navigating between groups of related content [1][2]. The Tabs.Root component serves as the top-level wrapper that manages the state, facilitating communication between the tab buttons and their corresponding panels [1][3]. Below are the key details regarding Tabs.Root: Assembly and Usage You import the Tabs component from @base-ui/react/tabs and use it as a container [1]: import { Tabs } from '@base-ui/react/tabs'; <Tabs.Root> <Tabs.List> <Tabs.Tab value="tab1">Tab 1</Tabs.Tab> <Tabs.Tab value="tab2">Tab 2</Tabs.Tab> </Tabs.List> <Tabs.Panel value="tab1">Panel 1</Tabs.Panel> <Tabs.Panel value="tab2">Panel 2</Tabs.Panel> </Tabs.Root> Key Props for Tabs.Root The Tabs.Root component accepts several props to control its behavior [1][4][5]: - value: The value of the currently active Tab. Use this for controlled components [4][5]. - defaultValue: The initial value of the active Tab. Use this for uncontrolled components. Defaults to 0 [1][4][5]. - orientation: Sets the layout flow direction. Options are 'horizontal' or 'vertical'. Defaults to 'horizontal' [1][4][5]. - onValueChange: A callback function invoked when the selected value changes [4][5]. - render: Allows you to replace the underlying HTML element (default is a div) or compose the component with your own logic [1][6]. For complete, up-to-date documentation, including API references and guides on styling and composition, visit the official Base UI documentation at https://base-ui.com/react/components/tabs [1][7].
Citations:
- 1: https://base-ui.com/react/components/tabs
- 2: https://www.infoq.com/news/2026/02/baseui-v1-accessible/
- 3: https://v6.mui.com/base-ui/react-tabs/
- 4: https://github.com/mui/base-ui/blob/d81ec002/packages/react/src/tabs/root/TabsRoot.tsx
- 5: https://cdn.jsdelivr.net/npm/@base-ui-components/react@1.0.0-rc.0/tabs/root/TabsRoot.d.ts
- 6: https://base-ui.com/react/handbook/composition
- 7: https://www.npmjs.com/package/@base-ui/react
Forward orientation to the Base UI root.
The current wrapper sets the CSS class for vertical tabs but strips orientation from props before spreading it onto TabsPrimitive.Root. Vertical tabs will keep Base UI’s default horizontal focus navigation and aria-orientation, so pass the wrapped value through.
Proposed fix
<TabsPrimitive.Root
+ orientation={orientation}
data-slot="tabs"
data-orientation={orientation}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function Tabs({ | |
| className, | |
| orientation = "horizontal", | |
| ...props | |
| }: React.ComponentProps<typeof TabsPrimitive.Root>) { | |
| }: TabsPrimitive.Root.Props) { | |
| return ( | |
| <TabsPrimitive.Root | |
| data-slot="tabs" | |
| className={cn("flex flex-col gap-2", className)} | |
| data-orientation={orientation} | |
| className={cn( | |
| "group/tabs flex gap-2 data-[orientation=horizontal]:flex-col", | |
| className, | |
| )} | |
| {...props} | |
| /> | |
| ); | |
| } | |
| function Tabs({ | |
| className, | |
| orientation = "horizontal", | |
| ...props | |
| }: TabsPrimitive.Root.Props) { | |
| return ( | |
| <TabsPrimitive.Root | |
| orientation={orientation} | |
| data-slot="tabs" | |
| data-orientation={orientation} | |
| className={cn( | |
| "group/tabs flex gap-2 data-[orientation=horizontal]:flex-col", | |
| className, | |
| )} | |
| {...props} | |
| /> | |
| ); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/shadcn/src/components/ui/tabs.tsx` around lines 8 - 24, Update the
Tabs wrapper to explicitly pass the resolved orientation value to
TabsPrimitive.Root after destructuring it, while preserving the existing
data-orientation styling and other props. This ensures Base UI receives
"vertical" when requested instead of falling back to horizontal behavior.
| <ShadCNComponents.Toggle.Toggle | ||
| className={cn( | ||
| className, | ||
| "data-[state=open]:bg-accent data-[state=closed]:text-accent-foreground", | ||
| "aria-expanded:bg-accent aria-expanded:text-accent-foreground", | ||
| variant === "compact" ? "h-6 min-w-6 p-0" : "", | ||
| )} | ||
| size={variant === "compact" ? "sm" : "default"} | ||
| aria-label={label} | ||
| onClick={onClick} | ||
| pressed={isSelected} | ||
| disabled={isDisabled} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Base UI Toggle component pressed state data attribute aria-pressed
💡 Result:
The Base UI Toggle component manages its pressed state primarily through the data attribute data-pressed [1][2][3]. When the toggle is in a pressed state, the data-pressed attribute is present on the component's root element [1][2][3]. This attribute is intended for styling purposes, allowing you to use CSS selectors such as [data-pressed] or Tailwind CSS classes like data-[pressed]:bg-blue-500 to apply specific styles when the button is active [3]. Regarding aria-pressed, while this is the standard WAI-ARIA attribute for indicating the state of a toggle button to assistive technologies [4][5], Base UI components are designed to handle accessibility automatically. The Toggle component internally manages the appropriate ARIA attributes based on its pressed state prop, ensuring that screen readers correctly interpret the element as a toggle button [3][6]. Users typically do not need to manually add or manage aria-pressed on the component itself, as the library handles this state synchronization as part of its accessible implementation [3][6]. Summary: - Data Attribute: data-pressed is used to indicate the pressed state for styling [1][3]. - ARIA Attribute: aria-pressed is managed internally by the component to ensure accessibility [3][6].
Citations:
- 1: https://base-ui.com/react/components/toggle
- 2: https://baseui-vue.com/docs/components/toggle
- 3: https://mintlify.wiki/mui/base-ui/components/toggle
- 4: [button] The Button Component mui/base-ui#2138
- 5: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-pressed
- 6: https://deepwiki.com/mui/base-ui/7.4-toggle-and-togglegroup
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Repository files matching Toolbar.tsx:"
fd -a 'Toolbar\.tsx$' . || true
echo
echo "Target snippet if present:"
if [ -f packages/shadcn/src/toolbar/Toolbar.tsx ]; then
wc -l packages/shadcn/src/toolbar/Toolbar.tsx
sed -n '80,110p' packages/shadcn/src/toolbar/Toolbar.tsx
fi
echo
echo "Search for Toggle and data-pressed/aria-expanded usage:"
rg -n "data-\[pressed\]|aria-expanded|pressed=\{isSelected\}|Toggle\.Toggle" packages/shadcn/src/toolbar/Toolbar.tsx packages -S || trueRepository: TypeCellOS/BlockNote
Length of output: 3961
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Base UI Toggle source references and package config:"
rg -n "\"`@base-ui`|base-ui|Toggle|pressed|data-pressed|aria-pressed" package.json packages package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null || true
echo
echo "Inspect shadcn Toggle wrapper/source candidates:"
fd -a 'Toggle\.(tsx|ts|jsx|js)$|components|ui|styled' packages/shadcn/src -t f | head -100Repository: TypeCellOS/BlockNote
Length of output: 42313
🌐 Web query:
Base UI Toggle component data state on pressed state
💡 Result:
In Base UI, the Toggle component's internal state is fundamentally driven by its pressed status [1][2]. When the toggle is in a pressed state, the component exposes this via the data attribute data-pressed on the underlying DOM element [1][3]. Key aspects of the Toggle state include: 1. Pressed State Management: The component uses a pressed boolean to track whether it is active [1][4]. This can be managed in a controlled way via the pressed and onPressedChange props, or in an uncontrolled way using defaultPressed [1][5]. 2. Data Attribute: When the toggle is pressed, the attribute data-pressed is automatically present on the root element [1][3]. This allows you to apply conditional styles using CSS data attribute selectors, such as data-[pressed]:bg-blue-500 [5]. 3. Integration with ToggleGroup: When a Toggle is placed inside a ToggleGroup, its pressed state is derived by checking if its specific value prop exists within the group's current value array [2]. In this context, the group acts as the source of truth for the pressed state of its child toggles [2]. The Toggle component also maintains a disabled state, exposed via the data-disabled attribute, which prevents user interaction [1][6].
Citations:
- 1: https://base-ui.com/react/components/toggle
- 2: https://deepwiki.com/mui/base-ui/7.4-toggle-and-togglegroup
- 3: https://baseui-vue.com/docs/components/toggle
- 4: https://app.unpkg.com/@base-ui/react@1.2.0/files/toggle/Toggle.d.ts
- 5: https://mintlify.wiki/mui/base-ui/components/toggle
- 6: https://mui-base-ui.mintlify.app/api/toggle
🌐 Web query:
Base UI Toggle component pressed state data attribute aria-pressed
💡 Result:
The Base UI Toggle component uses the data-pressed data attribute to indicate its pressed state [1][2][3]. When the Toggle is in the pressed state, the component applies the data-pressed attribute to the root element [1]. You can use this attribute for styling purposes with CSS attribute selectors, such as data-[pressed]:bg-blue-500 in Tailwind CSS or.toggle[data-pressed] in standard CSS [4]. While the component manages its accessibility state, it does not rely on aria-pressed as a data attribute; rather, it uses the data-pressed attribute to surface the internal state to the DOM for styling [1][4]. The component manages the underlying ARIA attributes required for accessibility (such as aria-pressed) automatically as part of its headless functionality [5].
Citations:
- 1: https://base-ui.com/react/components/toggle
- 2: https://baseui-vue.com/docs/components/toggle
- 3: https://base-ui-docs-solid.vercel.app/solid/components/toggle
- 4: https://mintlify.wiki/mui/base-ui/components/toggle
- 5: https://deepwiki.com/mui/base-ui/7.4-toggle-and-togglegroup
Use data-[pressed] for the selected toolbar highlight.
This Toggle renders as a pressed button via pressed={isSelected}, but the styling hook still targets aria-expanded, which is for disclosure triggers. Select styled state from the Toggle’s own state prefix, e.g. data-[state=on] if that was the existing shadcn pattern, or data-[pressed] for Base UI Toggle.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/shadcn/src/toolbar/Toolbar.tsx` around lines 91 - 101, The Toggle
styling in the toolbar targets aria-expanded instead of the Toggle’s pressed
state. Update the className in the Toggle.Toggle usage to use the established
pressed-state selector, preferably data-[pressed] for Base UI Toggle, while
preserving the existing accent highlight styles and compact variant classes.
|
|
||
| import * as React from "react"; | ||
| import * as AvatarPrimitive from "@radix-ui/react-avatar"; | ||
| import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar"; |
There was a problem hiding this comment.
let's mark changes in generated components with comments
Summary
This PR updates ShadCN for the
@blocknote/shadcnpackage. The main changes are migration from Radix UI to BaseUI and a new theming configuration. The components should all still look the same though.Rationale
Radix UI is being phased out and replaced by BaseUI.
Changes
General
shadcn add ...CLI command.components.jsonupdatedstyleandiconLibraryfields.Component-Specific
renderprop instead of Radix'sasChild.MenuTriggerWithPointerUpworkaround as it was specific to Radix.delayDurationprops todelay.data-[state=open]attributes. BaseUI automatically appliesaria-extendedwhich is also used as a selector for styled.--radix-*-available-height→--available-height.DropdownMenu.DropdownMenuLabelin aDropdownMenu.DropdownMenuGroupas this is required by BaseUI.editor.portalElement.alignItemWithTrigger={false}on all select elements to match existing behaviour. This controls whether a select dropdown always displays items below the trigger, or whether the selected item in the dropdown is positioned behind the trigger.data-horizontal→data-[orientation=horizontal],data-vertical→data-[orientation=vertical]."@/lib/utils"path replaced with"../../lib/utils".Impact
N/A
Testing
Manually tested, e2e tests pass.
Screenshots/Video
N/A
Checklist
Additional Notes
N/A
Summary by CodeRabbit