Qendrim UI

01What problem did you find?

A panel that is fine when left alone breaks when someone changes their mind

01What problem did you find?

A panel that is fine when left alone breaks when someone changes their mind

I am building Koba, where people review and correct receipts. A panel like that gets opened, edited and closed in whatever order someone decides, and most animated panels are only correct when nobody interrupts them.

The first panel here is one I broke on purpose, the way a quick implementation breaks: it scales its content, so its box jumps and its field is drawn squashed when the move is reversed.

The other is the library, given the same presses.

02Who was affected?

Whoever is halfway through an edit, and the engineer who has to build the panel

02Who was affected?

Whoever is halfway through an edit, and the engineer who has to build the panel

The bug lands on someone mid-task: correcting an amount, about to press save. This is the receipt review from the docs, with sample receipts.

I built this for the product engineer on the other side, who already knows Base UI, Radix or Motion and needs an inspector or a review drawer that keeps up. Nobody outside the project has used it yet.

03What was your hypothesis?

If the row is the panel, an interruption has nothing to break

If the row is the panel, then an interruption has nothing to break

The usual way joins two elements with an animation, a row and a panel, and that is where the copies, the lost focus and the stretched text come from. My bet was one element for its whole life: CSS decides its shape, and an engine moves it from wherever it is on screen, at the speed it already has.

The price is real layout on every frame. So before the final measurement I wrote down budgets for size and speed, and committed them on 6 November 2026.

04What was your first attempt?

The first engine passed every test I had

This is the project example built from the commit that froze the budgets. Open a row, type, close it halfway, open it again, and the text and the caret stay where they were. Every test was green.

The project inspector example at the commit that froze the budgets, in a wide window or a phone: a row opens into an editor, is typed in, closed halfway and reopened, and keeps its text

05What did later attempts look like, and what was learned?

A review found a jump my tests could not see

I had a second reviewer go through a clean clone with the code and the contract, and none of my conclusions. It found the panel jumping 355 px on the library's own bottom sheet. My engine assumed a box stays put when its size is locked, and a box anchored to the bottom does not. My detector had been reading height and nothing else.

Below is that same first build in a narrow window, photographed one frame of the page's clock at a time. One frame after the press the row has left the list and is coming in from the bottom edge.

The project example in a narrow window at the commit before the fix, where the pressed row has left the list and is arriving from the bottom edge
The same example at the commit with the fix, where the pressed row grows from where it was

17 ms after the press

The fix is commit 3c00fba, which measures where layout puts the box at the size it has on screen. The same review went through my comparison with Motion and plain CSS. Baselines were missing rules I had said they had, my Motion springs ran a 384 ms period against the library's 320 ms, and a Motion version about 30 lines longer passed everything. I fixed the harness and made that version a baseline.

An earlier draft showed the library well ahead, and that came from the harness

06How did you iterate and test?

I rebuilt the page three times in four days

06How did you iterate and test?

I rebuilt the page three times in four days

The library stopped changing on 6 November. The page that shows it did not. The first one, that morning, opened on a paragraph and four numbers, with the working panel further down.

By midday the stage was a list of projects, with a row of actions above it.

On the afternoon of 9 November it opened on the panel itself, moving between four layouts. That night it became the drafting sheet at the top of this story.

After the last change to the library, and again after each rebuild on 9 November, the whole browser suite passed three times in a row in Chromium, Firefox and WebKit. It grew from 507 tests to 655 on the way. To check the tests themselves I broke the library on purpose 55 times, one change at a time: 53 were caught, and I judged that the other 2 change nothing.

07What came of it?

A careful Motion version ties it, and 3 of 17 budgets were missed

07What came of it?

A careful Motion version ties it, and 3 of 17 budgets were missed

On the eight interruption scenarios the library has no violations, and neither does Motion with a measured height. So Motion can do it too, with about 30 more lines. What I can claim is the contract, tested, in 4.1 KB where Motion's layout animation is 44.1 KB.

Fixing the jump needs a second read of the layout at every request. That took the layout count in my reversal workload from 139 to 163 against a budget of 150, and pushed Surface to 4,245 bytes against 4,096 and Inspector to 6,838 against 6,500. I left the budgets where they were.

All of it is lab data from one Mac in headless browsers, with no real phone and no screen reader, and the package is not on npm.

08What would you do next?

Next is the layout count, real devices and a second person

08What would you do next?

Next is the layout count, real devices and a second person

The engine can skip the second read when a box is anchored the way it was last time, which should bring the layout count back under its budget.

After that it needs real phones, a session with a screen reader, and someone who is not me building with it.