A freshly mounted `CheckboxIndicator` is styled once before `data-starting-style`, so an enter transition runs backwards first

Open
#511 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
40/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
css, typescript
Domain
frontend

Research direction

Start by running the Solid snippet in the issue and logging the indicator's data-starting-style attribute on each frame. The payload names only CheckboxIndicator in @ui-sdk/solid and @ui-sdk/core and does not name files, so locate the checkbox indicator's mount and attribute-setting code in those packages. Done means the path shows one transitionrun with no transitioncancel, and the stroke-dashoffset runs forward from 1 to 0.

Written by the indexing model from the issue text.

Description

What happens

A CheckboxIndicator that mounts when its checkbox is checked gets one style pass without
data-starting-style before the attribute lands. A transition written the documented way
(the settled pose by default, the hidden pose under [data-starting-style]) therefore starts
from the settled value, moves towards the hidden pose while data-starting-style is present,
and is then cancelled and reversed once the attribute goes. The enter animation never starts
from the hidden pose: a tick drawn with stroke-dashoffset first erases part-way (0 → 0.59),
then draws back over a shortened, reversed transition.

Minimal reproduction

Solid, @ui-sdk/solid parts only, the tick drawn with a CSS transition:

import { Checkbox, CheckboxIndicator } from '@ui-sdk/solid/checkbox'

const css = `
[data-slot="checkbox-indicator"] path {
	stroke-dasharray: 1;
	stroke-dashoffset: 0;
	transition: stroke-dashoffset 80ms ease-out;
}
[data-slot="checkbox-indicator"][data-starting-style] path,
[data-slot="checkbox-indicator"][data-ending-style] path {
	stroke-dashoffset: 1;
}
`

export const Example = () => (
	<>
		<style>{css}</style>
		<label>
			<Checkbox>
				<CheckboxIndicator>
					<svg
						width="24"
						height="24"
						viewBox="0 0 24 24"
						fill="none"
						stroke="black"
					>
						<path d="M6 12L10 16L18 8" pathLength="1" />
					</svg>
				</CheckboxIndicator>
			</Checkbox>
			Accept
		</label>
	</>
)

Click the checkbox and read, every animation frame, the path's computed stroke-dashoffset
and whether the indicator has data-starting-style, plus the path's transitionrun /
transitioncancel events (ms from the first frame after the click):

[ms, stroke-dashoffset, data-starting-style]
[36, "0px",        true ]   first frame: drawn, although the starting style says 1
[53, "0.319005px", true ]   the transition runs towards 1 (erasing)
[69, "0.590207px", false]   the attribute is gone; the transition is cancelled...
[86, "0.286786px", false]   ...and reversed from 0.59 back to 0
[103,"0.0731598px",false]
[119,"0px",        false]
events: transitionrun 25, transitioncancel 72, transitionrun 72

The same shape in every run (four runs, two page loads): one transitionrun, a
transitioncancel, a second transitionrun. The first frame after the mount reads the
default pose (0px) with data-starting-style already present in the next one.

Versions
  • @ui-sdk/solid 0.1.0-beta.1, @ui-sdk/core 0.1.0-beta.1, Solid 2.0.0-rc.21
  • Chrome for Testing 156, driven by Playwright 1.64.1
Expected behavior

The indicator's first style pass includes data-starting-style (as @starting-style does for
a CSS-only enter), so a transition from the starting pose to the settled pose runs once,
forward, over its full duration: one transitionrun, no transitioncancel.

Workaround

Give the starting pose transition-duration: 0s: the jump into the starting pose is then
instant, and the enter transition starts from it at full duration.


Reproduced on @ui-sdk/core / @ui-sdk/solid 0.1.0-beta.2.

Dominant language
TypeScript
Stars
4.4k
Forks
122
Avg merge
3h 12m
Merged PRs (30d)
437

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from vercel-labs/ui

All issues in vercel-labs/ui

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.