Skip to content

Fix datepicker shifting a prefilled input on first open - #43119

Open
pardeyke wants to merge 1 commit into
twbs:mainfrom
pardeyke:datepicker-prefilled-input-shift
Open

pardeyke wants to merge 1 commit into
twbs:mainfrom
pardeyke:datepicker-prefilled-input-shift

Conversation

@pardeyke

@pardeyke pardeyke commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Description

A datepicker <input> with a value attribute jumps down by 4px the moment it receives focus, and stays there. The same happens after setSelectedDates() is called before the popup has been opened once. Inside .form-adorn the wrapper is affected instead of the input.

Vanilla Calendar Pro builds its popup lazily, on the first click or focus of the trigger. Until then context.mainElement is still the trigger itself. set() (which _parseInputValue() and setSelectedDates() call) marks the calendar as rendered, so VCP's show() skips its own first-click fallback and runs its positioning helper on the trigger: data-vc-position="bottom" plus inline left/top land on the input. Bootstrap's unscoped [data-vc-position="bottom"] { margin-block-start: .25rem } then matches the input and pushes it down. An empty input is not affected because VCP's fallback clicks the trigger first, which creates the popup.

This PR:

  • makes Datepicker#show() click the trigger first when VCP has not built its popup yet (context.inputModeInit is unset), mirroring what VCP does for an empty input, so the popup exists before it is positioned. A button trigger's click already runs the data API and shows the popup, so show() returns in that case instead of firing shown twice.
  • scopes the position margins in _datepicker.scss to [data-vc="calendar"], so a stray attribute on a trigger can no longer move it.
  • adds regression tests for a prefilled input, setSelectedDates() before the first show, a prefilled input inside .form-adorn, focus via the data API, and a button shown programmatically before its first click. All five fail on main.

Motivation & Context

Reproduction with the 6.0.0-alpha.1 CDN build: take the datepicker example from the docs and add value="2026-08-04" to the input. Click it: the field moves down 4px as the focus ring appears and the input now carries data-vc-position="bottom" and style="left: …; top: …". Remove the value and it does not move. Server-rendered forms (edit pages) nearly always prefill the value, so this hits most real-world uses of the datepicker.

Verified in Chrome with the built dist that the input, a .form-adorn wrapper, and a button trigger no longer move or receive VCP attributes, while the popup still opens and is positioned below the trigger.

The underlying cause is arguably in VCP (its show() guards on currentType instead of inputModeInit), but Bootstrap can avoid it on its side without waiting for an upstream release.

Type of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Refactoring (non-breaking change)
  • Breaking change (fix or feature that would change existing functionality)

Checklist

  • I have read the contributing guidelines
  • My code follows the code style of the project (using npm run lint)
  • My change introduces changes to the documentation
  • I have updated the documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed

Live previews

  • n/a (no docs change)

Related issues

None found.

EDIT:
https://codepen.io/editor/aloysiu5/pen/01a14f9c-e218-7ffa-bcc8-5179618dd13a

🤖 Generated with Claude Code

Vanilla Calendar Pro builds its popup on the first click or focus of the
trigger. Until then `context.mainElement` is still the trigger itself.
`set()` (a prefilled input value, `setSelectedDates()`) marks the
calendar as rendered, so VCP's `show()` skips its own first-click
fallback and positions the trigger instead of the popup: it writes
`data-vc-position` and inline `left`/`top` onto the input, where
`[data-vc-position="bottom"]` adds a top margin and the field jumps
down by 4px the moment it receives focus. The attributes are never
removed. Inside `.form-adorn` the wrapper gets them instead.

Click the trigger first when VCP has not built its popup yet, as VCP
does itself for an empty input, so the popup exists before it is
positioned. Scope the position margins to the calendar element so a
stray attribute on a trigger can no longer move it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@pardeyke
pardeyke requested review from a team as code owners October 18, 2026 16:06
@julien-deramond julien-deramond added v6 v6, the main branch accessibility Keyboard, screen readers, contrast, ARIA bug Something does not work as documented css Sass sources or compiled CSS js JavaScript or TypeScript sources and plugins labels Oct 18, 2026

This branch has not been deployed

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

Labels

accessibility Keyboard, screen readers, contrast, ARIA bug Something does not work as documented css Sass sources or compiled CSS js JavaScript or TypeScript sources and plugins v6 v6, the main branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants