frappe-ui is heading to a 1.0.0 tag. The breaking changes land as separate PRs. This issue is the single place that tracks all of them for Builder.
- Work top to bottom. Each section names the exact sites in this repo, with before/after.
- More sections get appended as more breaks land before the tag.
- Do not start until you bump the frappe-ui pin. Today it is
1.0.0-beta.21 in frontend/package.json.
- Full list of changes: migration guide.
| # |
Change |
PR |
Fails at build? |
| 1 |
$socket is no longer set by the plugin |
frappe/frappe-ui#948 |
No — throws at runtime |
| 2 |
Popover v0 API removed; Tooltip placement and #body renamed (14 Popover, 9 Tooltip) |
frappe/frappe-ui#956 |
No — every break is silent |
| 3 |
Dropdown placement, { group, items } and component: rows removed (11 sites) |
frappe/frappe-ui#957 |
No — silent; vue-tsc flags them |
1. $socket is no longer set by the plugin
PR: frappe/frappe-ui#948
frappe-ui 1.0.0 removes initSocket and the FrappeUI plugin's socketio option. The plugin no longer creates a socket.io connection.
Builder is the only app that used the plugin's socket instead of building its own.
1.1 What breaks
frontend/src/utils/realtimeHandler.ts:10:
this.socket = getCurrentInstance()!.appContext.config.globalProperties.$socket;
frontend/src/main.ts:17 calls app.use(FrappeUI) with no options. socketio used to default to true, so the plugin set $socket for you. It no longer does.
This is not a build failure. Reading $socket throws at runtime with a message naming the fix, so it will surface on the first page that opens a realtime connection rather than as undefined crashing somewhere else.
1.2 Fix
Create the connection in frontend/src/main.ts and assign it before app.mount():
import { io } from 'socket.io-client'
const host = window.location.hostname
const port = window.location.port ? ':9000' : ''
const protocol = port ? 'http' : 'https'
const siteName = import.meta.env.DEV ? host : window.site_name
app.config.globalProperties.$socket = io(
`${protocol}://${host}${port}/${siteName}`,
{ withCredentials: true },
)
That is exactly what initSocket did. Assigning your own replaces the guard, so nothing else changes.
Every other Frappe app already does this in its own src/socket.js, which is why Builder is the only one affected. Putting it in a frontend/src/socket.ts would match them.
Replaces #717.
2. Popover and Tooltip: the v0 API is gone
PR: frappe/frappe-ui#956
frappe-ui 1.0.0 removes the v0 Popover API and renames two things on Tooltip. Builder has 23 affected sites.
Nothing warns. Vue drops an unknown prop or slot in silence, so a missed site renders a popover with no trigger, an empty one, or a tooltip on the wrong edge — and the build stays green. Work the list.
Line numbers are against develop at eef1132.
Popover
| v0 |
v1 |
#target slot |
#trigger — it wires its own click, so drop the handler |
#body slot |
#default slot plus the bare prop — #body rendered outside the panel shell |
#body-main slot |
#default slot |
togglePopover slot prop |
toggle |
isOpen slot prop |
open |
placement="bottom-end" |
side="bottom" + align="end" (a bare placement="bottom" is align="center") |
trigger="hover" |
the HoverCard component |
<!-- before -->
<Popover placement="bottom-end">
<template #target="{ togglePopover }">
<Button label="Filter" @click="togglePopover" />
</template>
<template #body-main="{ close }">
<FilterPanel @done="close" />
</template>
</Popover>
<!-- after -->
<Popover side="bottom" align="end">
<template #trigger>
<Button label="Filter" />
</template>
<template #default="{ close }">
<FilterPanel @done="close" />
</template>
</Popover>
The leftover click handler is the one that bites. #trigger already toggles, so keeping your own @click toggles twice and the popover never opens.
#body and #body-main are not the same slot. #body-main rendered inside the panel, so it is plain #default. #body replaced the panel, so it needs bare as well — without it your content lands inside a second panel.
<!-- before -->
<Popover>
<template #body><EmojiPicker /></template>
</Popover>
<!-- after -->
<Popover bare>
<EmojiPicker />
</Popover>
14 sites:
frontend/src/components/AIPageGeneratorModal.vue:76 — #target slot, #body-main slot, placement prop, togglePopover slot prop.
frontend/src/components/ArrayInput.vue:2 — #target slot, #body slot, placement prop.
frontend/src/components/BackgroundHandler.vue:2 — #target slot, #body slot, placement prop, togglePopover slot prop.
frontend/src/components/BuilderToolbar.vue:29 — #target slot, #body slot, placement prop, isOpen slot prop, togglePopover slot prop.
frontend/src/components/ComponentUpdates.vue:2 — #target slot, #body slot, placement prop, togglePopover slot prop.
frontend/src/components/Controls/ColorPicker.vue:2 — #target slot, #body slot, placement prop, isOpen slot prop, togglePopover slot prop.
frontend/src/components/Controls/GradientEditor.vue:27 — #target slot, #body slot, placement prop, togglePopover slot prop.
frontend/src/components/Controls/InputLabel.vue:4 — #target slot, #body slot, placement prop, trigger prop.
frontend/src/components/Controls/SearchBlock.vue:22 — #target slot, #body slot, isOpen slot prop, togglePopover slot prop.
frontend/src/components/ImageUploadInput.vue:12 — #target slot, #body slot, placement prop, togglePopover slot prop.
frontend/src/components/ObjectInput.vue:2 — #target slot, #body slot, placement prop.
frontend/src/components/PropsEditor.vue:7 — #target slot, #body slot, placement prop.
frontend/src/components/PropsEditor.vue:82 — #target slot, #body slot, placement prop.
frontend/src/components/ShadowHandler.vue:2 — #target slot, #body slot, placement prop, togglePopover slot prop.
Tooltip
| v0 |
v1 |
placement="top" |
side="top" |
arrowClass |
[data-slot="arrow"] in CSS, or offset to shift the bubble |
#default stays the trigger. That inversion is deliberate and is not changing.
9 sites:
frontend/src/components/BuilderLeftPanel.vue:12 — placement prop.
frontend/src/components/BuilderToolbar.vue:77 — arrowClass.
frontend/src/components/BuilderToolbar.vue:107 — arrowClass.
frontend/src/components/BuilderToolbar.vue:114 — arrowClass.
frontend/src/components/BuilderToolbar.vue:126 — arrowClass.
frontend/src/components/BuilderToolbar.vue:130 — arrowClass.
frontend/src/components/ComponentUpdates.vue:4 — arrowClass.
frontend/src/components/Modals/TokenManager.vue:175 — placement prop.
frontend/src/components/Modals/TokenManager.vue:201 — placement prop.
Full before/after for all of it: migration guide.
3. Dropdown: placement, { group, items } and component: rows are gone
PR: frappe/frappe-ui#957
frappe-ui 1.0.0 removes three shapes from Dropdown (ContextMenu shares the option types). Builder has 11 affected sites.
Nothing fails the build. A placement prop is dropped and the menu shifts to the default alignment; a { group, items } group resolves to zero options and renders an empty menu; a component: row renders as a plain action row using its label, which for most of these rows is empty. Dev builds log a console warning for the last two, and the removed keys stay in the types as never, so vue-tsc names every site. Work the list.
Line numbers are against develop at 0c8a813.
placement → align
| before |
after |
placement="right" |
align="end" |
placement="center" |
align="center" |
placement="left" |
delete the prop — start is the default |
4 sites:
frontend/src/components/DashboardSidebar.vue:62 — right.
frontend/src/components/MainMenu.vue:2 — left — just delete it.
frontend/src/components/PageClientScriptManager.vue:43 — right.
frontend/src/components/Settings/GlobalDomains.vue:23 — right.
{ group, items } → { group, options }
Same key, new name; nothing else about the group changes:
// before
{ group: __('Actions'), hideLabel: true, items: [...] }
// after
{ group: __('Actions'), hideLabel: true, options: [...] }
7 sites:
frontend/src/components/DashboardSidebar.vue:159.
frontend/src/components/DashboardSidebar.vue:170.
frontend/src/components/DashboardSidebar.vue:191.
frontend/src/components/MainMenu.vue:48.
frontend/src/components/MainMenu.vue:55.
frontend/src/components/MainMenu.vue:88.
frontend/src/components/PageActionsDropdown.vue:7 — inline in the template.
Full before/after: migration guide.
frappe-ui is heading to a
1.0.0tag. The breaking changes land as separate PRs. This issue is the single place that tracks all of them for Builder.1.0.0-beta.21infrontend/package.json.$socketis no longer set by the pluginPopoverv0 API removed;Tooltipplacementand#bodyrenamed (14 Popover, 9 Tooltip)placement,{ group, items }andcomponent:rows removed (11 sites)vue-tscflags them1.
$socketis no longer set by the pluginPR: frappe/frappe-ui#948
frappe-ui 1.0.0 removes
initSocketand theFrappeUIplugin'ssocketiooption. The plugin no longer creates a socket.io connection.Builder is the only app that used the plugin's socket instead of building its own.
1.1 What breaks
frontend/src/utils/realtimeHandler.ts:10:frontend/src/main.ts:17callsapp.use(FrappeUI)with no options.socketioused to default totrue, so the plugin set$socketfor you. It no longer does.This is not a build failure. Reading
$socketthrows at runtime with a message naming the fix, so it will surface on the first page that opens a realtime connection rather than asundefinedcrashing somewhere else.1.2 Fix
Create the connection in
frontend/src/main.tsand assign it beforeapp.mount():That is exactly what
initSocketdid. Assigning your own replaces the guard, so nothing else changes.Every other Frappe app already does this in its own
src/socket.js, which is why Builder is the only one affected. Putting it in afrontend/src/socket.tswould match them.Replaces #717.
2. Popover and Tooltip: the v0 API is gone
PR: frappe/frappe-ui#956
frappe-ui 1.0.0 removes the v0
PopoverAPI and renames two things onTooltip. Builder has 23 affected sites.Nothing warns. Vue drops an unknown prop or slot in silence, so a missed site renders a popover with no trigger, an empty one, or a tooltip on the wrong edge — and the build stays green. Work the list.
Line numbers are against
developateef1132.Popover
#targetslot#trigger— it wires its own click, so drop the handler#bodyslot#defaultslot plus thebareprop —#bodyrendered outside the panel shell#body-mainslot#defaultslottogglePopoverslot proptoggleisOpenslot propopenplacement="bottom-end"side="bottom"+align="end"(a bareplacement="bottom"isalign="center")trigger="hover"HoverCardcomponentThe leftover click handler is the one that bites.
#triggeralready toggles, so keeping your own@clicktoggles twice and the popover never opens.#bodyand#body-mainare not the same slot.#body-mainrendered inside the panel, so it is plain#default.#bodyreplaced the panel, so it needsbareas well — without it your content lands inside a second panel.14 sites:
frontend/src/components/AIPageGeneratorModal.vue:76— #target slot, #body-main slot, placement prop, togglePopover slot prop.frontend/src/components/ArrayInput.vue:2— #target slot, #body slot, placement prop.frontend/src/components/BackgroundHandler.vue:2— #target slot, #body slot, placement prop, togglePopover slot prop.frontend/src/components/BuilderToolbar.vue:29— #target slot, #body slot, placement prop, isOpen slot prop, togglePopover slot prop.frontend/src/components/ComponentUpdates.vue:2— #target slot, #body slot, placement prop, togglePopover slot prop.frontend/src/components/Controls/ColorPicker.vue:2— #target slot, #body slot, placement prop, isOpen slot prop, togglePopover slot prop.frontend/src/components/Controls/GradientEditor.vue:27— #target slot, #body slot, placement prop, togglePopover slot prop.frontend/src/components/Controls/InputLabel.vue:4— #target slot, #body slot, placement prop, trigger prop.frontend/src/components/Controls/SearchBlock.vue:22— #target slot, #body slot, isOpen slot prop, togglePopover slot prop.frontend/src/components/ImageUploadInput.vue:12— #target slot, #body slot, placement prop, togglePopover slot prop.frontend/src/components/ObjectInput.vue:2— #target slot, #body slot, placement prop.frontend/src/components/PropsEditor.vue:7— #target slot, #body slot, placement prop.frontend/src/components/PropsEditor.vue:82— #target slot, #body slot, placement prop.frontend/src/components/ShadowHandler.vue:2— #target slot, #body slot, placement prop, togglePopover slot prop.Tooltip
placement="top"side="top"arrowClass[data-slot="arrow"]in CSS, oroffsetto shift the bubble#defaultstays the trigger. That inversion is deliberate and is not changing.9 sites:
frontend/src/components/BuilderLeftPanel.vue:12— placement prop.frontend/src/components/BuilderToolbar.vue:77— arrowClass.frontend/src/components/BuilderToolbar.vue:107— arrowClass.frontend/src/components/BuilderToolbar.vue:114— arrowClass.frontend/src/components/BuilderToolbar.vue:126— arrowClass.frontend/src/components/BuilderToolbar.vue:130— arrowClass.frontend/src/components/ComponentUpdates.vue:4— arrowClass.frontend/src/components/Modals/TokenManager.vue:175— placement prop.frontend/src/components/Modals/TokenManager.vue:201— placement prop.Full before/after for all of it: migration guide.
3. Dropdown:
placement,{ group, items }andcomponent:rows are gonePR: frappe/frappe-ui#957
frappe-ui 1.0.0 removes three shapes from
Dropdown(ContextMenushares the option types). Builder has 11 affected sites.Nothing fails the build. A
placementprop is dropped and the menu shifts to the default alignment; a{ group, items }group resolves to zero options and renders an empty menu; acomponent:row renders as a plain action row using itslabel, which for most of these rows is empty. Dev builds log a console warning for the last two, and the removed keys stay in the types asnever, sovue-tscnames every site. Work the list.Line numbers are against
developat0c8a813.placement→alignplacement="right"align="end"placement="center"align="center"placement="left"startis the default4 sites:
frontend/src/components/DashboardSidebar.vue:62—right.frontend/src/components/MainMenu.vue:2—left — just delete it.frontend/src/components/PageClientScriptManager.vue:43—right.frontend/src/components/Settings/GlobalDomains.vue:23—right.{ group, items }→{ group, options }Same key, new name; nothing else about the group changes:
7 sites:
frontend/src/components/DashboardSidebar.vue:159.frontend/src/components/DashboardSidebar.vue:170.frontend/src/components/DashboardSidebar.vue:191.frontend/src/components/MainMenu.vue:48.frontend/src/components/MainMenu.vue:55.frontend/src/components/MainMenu.vue:88.frontend/src/components/PageActionsDropdown.vue:7— inline in the template.Full before/after: migration guide.