You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
public/components/otp.js is a vanilla JS OTP input controller (~100 lines) loaded as a <script> tag directly inside the InputOTP component (app_crates/registry/src/ui/input_otp.rs). It manipulates the DOM to sync a hidden <input> value with visible slot elements and manage focus/caret state.
What the current JS does
initContainer(root) // bootstraps a single [data-otp-root] container
initAll() // queries all containers and calls initContainer
MutationObserver // watches for dynamically added OTP components (Leptos hydration)
The implementation:
Finds the hidden <input data-otp-input> inside the container
For each [data-otp-slot] (sorted by data-otp-index):
Updates [data-otp-char] text content with the character at that index
Sets data-active attribute based on cursor position
Shows/hides [data-otp-caret] depending on active + empty state
Adds a click listener on each slot → focuses the hidden input
Filters beforeinput to digits only
Listens to input, keydown, focus, blur → calls update()
Uses a MutationObserver on document.body to catch containers added after Leptos hydration
Goal
Replace otp.js with a pure Rust module using web_sys, eliminating the JS file and the <script> tag from InputOTP.
The Rust implementation should:
Use web_sys APIs: Document, Element, HtmlInputElement, EventListener, MutationObserver
Wire up all the same event listeners (click, beforeinput, input, keydown, focus, blur)
Replicate the update() logic (slot char sync, active state, caret visibility)
Context
public/components/otp.jsis a vanilla JS OTP input controller (~100 lines) loaded as a<script>tag directly inside theInputOTPcomponent (app_crates/registry/src/ui/input_otp.rs). It manipulates the DOM to sync a hidden<input>value with visible slot elements and manage focus/caret state.What the current JS does
The implementation:
<input data-otp-input>inside the container[data-otp-slot](sorted bydata-otp-index):[data-otp-char]text content with the character at that indexdata-activeattribute based on cursor position[data-otp-caret]depending on active + empty stateclicklistener on each slot → focuses the hidden inputbeforeinputto digits onlyinput,keydown,focus,blur→ callsupdate()MutationObserverondocument.bodyto catch containers added after Leptos hydrationGoal
Replace
otp.jswith a pure Rust module usingweb_sys, eliminating the JS file and the<script>tag fromInputOTP.The Rust implementation should:
web_sysAPIs:Document,Element,HtmlInputElement,EventListener,MutationObserverclick,beforeinput,input,keydown,focus,blur)update()logic (slot char sync, active state, caret visibility)MutationObserver(same as the JS version — see howlock_scroll.jswas replaced in PR refactor(hooks): replace lock_scroll.js with Rust web_sys implementation #21 for reference)Files involved
public/components/otp.js— the file to deleteapp_crates/registry/src/ui/input_otp.rs— remove<script src="/components/otp.js" />, wire in the Rust init callpublic/registry/styles/default/input_otp.md— update the registry snapshotReference
PR #21 replaced
lock_scroll.jswith Rust using the same pattern — good starting point.