Put the otp input after its boxes

A seventh box appeared when the field took focus.

daisyUI positions each otp box with nth-child, which counts *every* child of the
container, not just the spans. With the input as the first child, all six boxes
shifted one stride right and the container matched :has(>span:nth-child(7)), so
it grew to seven strides wide. The phantom box was the ::after active-box marker
-- transparent until :focus-within gives it an outline -- sitting in the empty
stride that the off-by-one had opened up.

The input goes last, which is also how daisyUI's own examples order it. A test
counts the boxes ahead of the input so this cannot come back.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-13 23:16:35 +02:00
parent fa213d95ee
commit add1ee87ae
2 changed files with 24 additions and 9 deletions

View File

@@ -43,20 +43,26 @@
{% with icon=field|field_icon %}
{% if field|is_otp %}
{% comment %}
daisyUI's otp is one input overlaid on the boxes, and it sizes itself from
its `span` children — so the sr-only label goes OUTSIDE the container, or it
would count as a seventh box and throw the width off.
daisyUI's otp is one input overlaid on the boxes. Child order is load-bearing:
it places each box with `nth-child`, which counts *every* child, not just the
spans — so the input must come LAST. Put it first and all six boxes shift one
stride right, the container matches :has(>span:nth-child(7)) and grows to
seven strides, and the ::after active-box marker (invisible until focus) shows
up in the gap as a phantom seventh box.
For the same reason the sr-only label lives outside the container: another
child would throw the count off again.
{% endcomment %}
{% if attrs.unlabeled %}<label class="sr-only" for="{{ field.id_for_label }}">{{ field.label }}</label>{% endif %}
<div class="flex justify-center">
<div class="otp otp-lg" data-otp>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
{{ field|as_otp }}
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
{% elif icon %}