Skip to content

fix(bindable): Fix bindable initial value precedence in Vue/Svelte#3218

Merged
segunadebayo merged 3 commits into
chakra-ui:mainfrom
Hwacc:fix/vue-bindable
Jul 20, 2026
Merged

fix(bindable): Fix bindable initial value precedence in Vue/Svelte#3218
segunadebayo merged 3 commits into
chakra-ui:mainfrom
Hwacc:fix/vue-bindable

Conversation

@Hwacc

@Hwacc Hwacc commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Closes # chakra-ui/ark#3942

📝 Description

In @ark-ui/vue Drawer, the first open after page mount does not play the CSS open animation. Computed style on Drawer.Content shows animation: none (inline animation: none !important). Closing works normally; opening a second time plays the open animation as expected.

Root Cause

1. Vue bindable drops defaultValue: null

In @zag-js/vue:

// packages/frameworks/vue/src/bindable.ts
const initial = props().defaultValue ?? props().value

In Drawer machine context:

dragOffset: bindable(() => ({
  defaultValue: null,
}))

Because ?? treats null as missing:

null ?? undefined  →  undefined

So on mount, context.get("dragOffset") is undefined, not null.

Compare React / Solid (works correctly):

const initial = props().value ?? props().defaultValue
// undefined ?? null → null

BTW, Svelte uses the same defaultValue ?? value pattern as Vue

2. Drawer treats non-null as “dragging”

In @zag-js/drawer connect:

const dragging = dragOffset !== null   //  undefined !== null  →  true

So immediately after mount (drawer still closed):

  • api.dragging === true
  • Content gets data-dragging / data-swiping
  • transition-duration: 0s is applied

3. First open entry suppresses CSS animation

open state entry includes deferClearDragOffset:

deferClearDragOffset({ context, refs, scope }) {
  const dragOffset = context.get("dragOffset")
  if (dragOffset === null) return  // undefined === null → false; does NOT return
  contentEl.style.setProperty("animation", "none", "important")
  backdropEl.style.setProperty("animation", "none", "important")
  raf(() => {
    refs.get("swipeSession").resetDragOffset()
    context.set("dragOffset", null)
  })
}

Intent: after swipe-to-open, temporarily disable CSS animations so they do not fight transform-driven settle.

Bug: first click-to-open also hits this path because dragOffset is undefined, so open CSS animations are killed with !important.

4. Why the second open works

  • First open’s raf eventually runs context.set("dragOffset", null)
  • Close runs clearSwipeOpenAnimation, which removeProperty("animation")
  • Later opens see real nulldeferClearDragOffset early-returns → CSS open animation runs

💣 Is this a breaking change (Yes/No): No

Addition

Since this default value binding issue has only surfaced in the Drawer component so far, I'm not yet certain whether it could affect other components as well. Fixing it as soon as possible will help align the behavior of the Vue and Svelte implementations with React.

P.S. Special thanks to Cursor Grok 4.5 model for helping quickly pinpoint this subtle issue.

@changeset-bot

changeset-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ba1efdf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 86 packages
Name Type
@zag-js/vue Patch
@zag-js/svelte Patch
svelte-kit-starter Patch
@zag-js/anatomy-icons Patch
@zag-js/anatomy Patch
@zag-js/core Patch
@zag-js/docs Patch
@zag-js/preact Patch
@zag-js/react Patch
@zag-js/solid Patch
@zag-js/vanilla Patch
@zag-js/accordion Patch
@zag-js/angle-slider Patch
@zag-js/async-list Patch
@zag-js/avatar Patch
@zag-js/carousel Patch
@zag-js/cascade-select Patch
@zag-js/checkbox Patch
@zag-js/clipboard Patch
@zag-js/collapsible Patch
@zag-js/color-picker Patch
@zag-js/combobox Patch
@zag-js/date-input Patch
@zag-js/date-picker Patch
@zag-js/dialog Patch
@zag-js/drawer Patch
@zag-js/editable Patch
@zag-js/file-upload Patch
@zag-js/floating-panel Patch
@zag-js/hover-card Patch
@zag-js/image-cropper Patch
@zag-js/listbox Patch
@zag-js/marquee Patch
@zag-js/menu Patch
@zag-js/navigation-menu Patch
@zag-js/number-input Patch
@zag-js/pagination Patch
@zag-js/password-input Patch
@zag-js/pin-input Patch
@zag-js/popover Patch
@zag-js/presence Patch
@zag-js/progress Patch
@zag-js/qr-code Patch
@zag-js/radio-group Patch
@zag-js/rating-group Patch
@zag-js/scroll-area Patch
@zag-js/select Patch
@zag-js/signature-pad Patch
@zag-js/slider Patch
@zag-js/splitter Patch
@zag-js/steps Patch
@zag-js/switch Patch
@zag-js/tabs Patch
@zag-js/tags-input Patch
@zag-js/timer Patch
@zag-js/toast Patch
@zag-js/toc Patch
@zag-js/toggle-group Patch
@zag-js/toggle Patch
@zag-js/tooltip Patch
@zag-js/tour Patch
@zag-js/tree-view Patch
@zag-js/store Patch
@zag-js/types Patch
@zag-js/aria-hidden Patch
@zag-js/auto-resize Patch
@zag-js/collection Patch
@zag-js/color-utils Patch
@zag-js/utils Patch
@zag-js/date-utils Patch
@zag-js/dismissable Patch
@zag-js/dom-query Patch
@zag-js/file-utils Patch
@zag-js/focus-trap Patch
@zag-js/focus-visible Patch
@zag-js/highlight-word Patch
@zag-js/hotkeys Patch
@zag-js/i18n-utils Patch
@zag-js/interact-outside Patch
@zag-js/json-tree-utils Patch
@zag-js/live-region Patch
@zag-js/popper Patch
@zag-js/rect-utils Patch
@zag-js/remove-scroll Patch
@zag-js/scroll-snap Patch
@zag-js/stringify-state Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
zag-nextjs Ready Ready Preview Jul 20, 2026 10:42am
zag-solid Ready Ready Preview Jul 20, 2026 10:42am
zag-svelte Ready Ready Preview Jul 20, 2026 10:42am
zag-vue Ready Ready Preview Jul 20, 2026 10:42am
zag-website Ready Ready Preview Jul 20, 2026 10:42am

Request Review

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.

2 participants