Firefox: mathVirtualKeyboard.show() blocks for ~1.2s+ even when the keyboard DOM already exists
Summary
We are seeing a Firefox-only performance issue in MathLive's virtual keyboard path.
- MathLive version:
0.108.3
- Firefox version:
152.0.3
- OS: Windows 11, build
26100
- Integration mode:
mathVirtualKeyboardPolicy = "manual"
- Integration behavior:
- call
window.mathVirtualKeyboard.show() on mathfield focus
- call
window.mathVirtualKeyboard.hide() on blur
Chrome does not reproduce the same issue.
Observed Behavior
In Firefox, window.mathVirtualKeyboard.show() blocks synchronously for about 1.2s to 3.3s.
This affects:
- first open
- reopen after blur
- reopen after switching between mathfields if a fresh
show() call happens
We can make hide feel immediate in app code, and we can also keep the keyboard visible across direct mathfield-to-mathfield transitions. Those app-level fixes improve UX, but they do not remove the main show() stall.
Strongest Evidence
We added logs immediately before and after window.mathVirtualKeyboard.show().
Typical timings:
- before any workaround:
- first opens around
2200ms to 3300ms
- after a hidden warm-up (
show() + hide() once in the background):
- first real open still around
1623ms
- later opens around
1437ms to 1869ms
- after prebuilding the keyboard DOM without showing it:
- prebuild itself took about
95ms
- first real open still took about
1192ms
- reopen after blur still took about
1228ms
The key point is:
- before prebuild:
keyboardFound: false
- after prebuild:
keyboardFound: true
- on the next focus,
show() is still slow even though the keyboard already exists
That strongly suggests the remaining cost is not just first-time DOM creation.
Why This Looks Like a MathLive show()-Path Issue
The timing is captured immediately around:
const t0 = performance.now();
window.mathVirtualKeyboard.show();
console.log(performance.now() - t0);
So the blocking time is inside MathLive's show() path itself.
Additional Observations
- Firefox focus ordering around mathfield-to-mathfield transitions is less reliable than Chrome
- We handled that locally by not hiding the keyboard when focus is clearly moving directly to another mathfield
- When we avoid a fresh
show() call and simply keep the existing keyboard visible, the transition is effectively immediate
That suggests the main remaining UX problem is tied specifically to show(), not to ordinary focus handoff.
Likely Hotspot in the Current Source
From local inspection of src/virtual-keyboard/virtual-keyboard.ts, the most likely hotspot appears to be synchronous work that still happens during show() even when _element already exists:
observer.observe(plate)
plate.offsetHeight / layout measurement
- body padding adjustment
this.currentLayer = this.latentLayer
currentLayer -> render()
render() walks visible keycaps and rewrites their markup
I have not proven which of those is the dominant bottleneck yet, but the data now points more strongly at this area than at first-time keyboard construction.
Minimal Repro
I prepared a standalone repro HTML with:
- MathLive
0.108.3 from CDN
- two
math-field elements
- direct timing logs around
show() and hide()
- a hidden warm-up path
- a prebuild path to separate creation cost from
show() cost
Questions
- Is this a known Firefox performance issue in the virtual keyboard path?
- Even when the keyboard element already exists, should
show() still be expected to block for around 1.2s in Firefox?
- Is
show() doing expensive synchronous rerender work on every open by design?
- Is there a recommended way to pre-initialize the keyboard without still paying the reopen cost?
- Is there a recommended strategy to keep the keyboard mounted or visible across field-to-field transitions on Firefox?
Local Patch Candidate We Are Investigating
We also prepared a local candidate patch in a clone of the MathLive repo that tries to reduce redundant reopen work by:
- avoiding
currentLayer churn when the active layer is already correct
- reusing a cached plate height before falling back to forced layout reads
This candidate builds, but we have not yet verified runtime improvement in Firefox.
So far this should be treated as a debugging lead, not as a validated fix.
Firefox:
mathVirtualKeyboard.show()blocks for ~1.2s+ even when the keyboard DOM already existsSummary
We are seeing a Firefox-only performance issue in MathLive's virtual keyboard path.
0.108.3152.0.326100mathVirtualKeyboardPolicy = "manual"window.mathVirtualKeyboard.show()on mathfield focuswindow.mathVirtualKeyboard.hide()on blurChrome does not reproduce the same issue.
Observed Behavior
In Firefox,
window.mathVirtualKeyboard.show()blocks synchronously for about1.2sto3.3s.This affects:
show()call happensWe can make hide feel immediate in app code, and we can also keep the keyboard visible across direct mathfield-to-mathfield transitions. Those app-level fixes improve UX, but they do not remove the main
show()stall.Strongest Evidence
We added logs immediately before and after
window.mathVirtualKeyboard.show().Typical timings:
2200msto3300msshow()+hide()once in the background):1623ms1437msto1869ms95ms1192ms1228msThe key point is:
keyboardFound: falsekeyboardFound: trueshow()is still slow even though the keyboard already existsThat strongly suggests the remaining cost is not just first-time DOM creation.
Why This Looks Like a MathLive
show()-Path IssueThe timing is captured immediately around:
So the blocking time is inside MathLive's
show()path itself.Additional Observations
show()call and simply keep the existing keyboard visible, the transition is effectively immediateThat suggests the main remaining UX problem is tied specifically to
show(), not to ordinary focus handoff.Likely Hotspot in the Current Source
From local inspection of
src/virtual-keyboard/virtual-keyboard.ts, the most likely hotspot appears to be synchronous work that still happens duringshow()even when_elementalready exists:observer.observe(plate)plate.offsetHeight/ layout measurementthis.currentLayer = this.latentLayercurrentLayer->render()render()walks visible keycaps and rewrites their markupI have not proven which of those is the dominant bottleneck yet, but the data now points more strongly at this area than at first-time keyboard construction.
Minimal Repro
I prepared a standalone repro HTML with:
0.108.3from CDNmath-fieldelementsshow()andhide()show()costQuestions
show()still be expected to block for around1.2sin Firefox?show()doing expensive synchronous rerender work on every open by design?Local Patch Candidate We Are Investigating
We also prepared a local candidate patch in a clone of the MathLive repo that tries to reduce redundant reopen work by:
currentLayerchurn when the active layer is already correctThis candidate builds, but we have not yet verified runtime improvement in Firefox.
So far this should be treated as a debugging lead, not as a validated fix.