htmlradio-buttonbootstrap-5radio-group

Radio button (with nested controls) not reached when using tab key


My code works 100% as expected. All controls can be reached using the tab key or the arrow keys, except for the 2nd radio button, labeled "No screening", which is never reached.

Is there a simple solution to fix that or should I opt for a different UI layout?

See the code ...

/* Just some simple (Bootstrap) formatting. Nothing interesting. */

* {
  padding: 3px;
}

.control-group {
  margin-bottom: 5px;
}

.control-label {
  font-weight: bold;
}

label {
  display: inline-block;
}

.form-check {
  padding-left: 0;
  display: block;
  min-height: 1.5rem;
  margin-bottom: .125rem;
}

input {
  margin: 0;
}

button {
  border: 1px solid #000;
}

.btn {
  display: inline-block;
  text-align: center;
  text-decoration: none;
  vertical-align: middle;
  cursor: pointer;
  user-select: none;
}

.card.screening {
  margin-left: 2rem;
  width: 30rem;
  padding: 10px;
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background-clip: border-box;
  border: 1px solid #999;
}

.card-text:last-child {
  margin-bottom: 0;
}

.top-spacer {
  margin-top: 10px;
}

.note {
  font-size: small;
}
<form action="process.php" method="POST">
  <div class="control-group">
    <label class="control-label">Reason upload *</label>
    <div class="controls">
      <div class="form-check">
        <input type="radio" id="reasonUploadScreening" name="reasonUpload" value="screening" autocomplete="off" tabindex="0">
        <label class="btn" for="reasonUploadScreening">Screening&nbsp;
                    <select id="screeningId" name="screeningId" class="field">
                        <option value="" disabled="" selected="">Select a screening</option>
                        <option value="20240328-1318">20240328-1318 John Doe (26-02-1968)</option>
                        <option value="20240328-1318">20240328-1604 [Anonymous]</option>
                        <option value="20240201-1575">20240201-1575 Jane Smith (11-11-1957)</option>
                        <option value="20240201-1100">20240201-1100 Peter Johnson (21-01-1980)</option></select>
                </label>
        <div class="card screening top-spacer">
          <div class="card-text">
            <div class="control-group">
              <label class="control-label">Number of images *</label>
              <div class="controls">
                <input type="radio" id="numberOfImages2" name="numberOfImages" value="2" autocomplete="off">
                <label class="btn" for="numberOfImages2">Two images (Single-field)</label>
                <input type="radio" id="numberOfImages4" name="numberOfImages" value="4" autocomplete="off">
                <label class="btn" for="numberOfImages4">Four images (Two-field)</label>
              </div>
            </div>
            <div class="control-group">
              <label class="control-label">Specify images *</label>
              <div class="controls">
                <input type="radio" id="specImgYes" name="specImg" value="1" autocomplete="off">
                <label class="btn" for="specImgYes">Yes</label>
                <input type="radio" id="specImgNo" name="specImg" value="0" autocomplete="off">
                <label class="btn" for="specImgNo">No</label>
              </div>
            </div>
            <div class="control-group">
              <label class="control-label">Mydriatics (dilating eye drops) used *</label>
              <div class="controls">
                <input type="radio" id="mydriasisYes" name="mydriasis" value="%s" autocomplete="off">
                <label class="btn" for="mydriasisYes">Yes</label>
                <input type="radio" id="mydriasisNo" name="mydriasis" value="%s" autocomplete="off">
                <label class="btn" for="mydriasisNo">No</label>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="form-check">
        <input type="radio" id="reasonUploadNoSreening" name="reasonUpload" value="noScreening" autocomplete="off" tabindex="0">
        <label class="btn" for="reasonUploadNoSreening">No screening</label>
        <div class="card screening top-spacer">
          <div class="card-text">
            <span class="note">Max. 200 images. The images will be visible to all users.</span>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="control-group  top-spacer">
    <div class="controls">
      <button value="submit" name="submit">Submit</button>
    </div>
  </div>
  <p class="note top-spacer">Fields marked with * are required.</p>
</form>


Solution

  • The "No screening" along with "Screening" radio is the part of the "reasonUpload" group, and is skipped only when one of them is selected:

    Example: "No screening" is skipped, because "Screening" is selected (need to use arrow keys):

    /* Just some simple (Bootstrap) formatting. Nothing interesting. */
    
    * {
      padding: 3px;
    }
    
    .control-group {
      margin-bottom: 5px;
    }
    
    .control-label {
      font-weight: bold;
    }
    
    label {
      display: inline-block;
    }
    
    .form-check {
      padding-left: 0;
      display: block;
      min-height: 1.5rem;
      margin-bottom: .125rem;
    }
    
    input {
      margin: 0;
    }
    
    button {
      border: 1px solid #000;
    }
    
    .btn {
      display: inline-block;
      text-align: center;
      text-decoration: none;
      vertical-align: middle;
      cursor: pointer;
      user-select: none;
    }
    
    .card.screening {
      margin-left: 2rem;
      width: 30rem;
      padding: 10px;
    }
    
    .card {
      position: relative;
      display: flex;
      flex-direction: column;
      background-clip: border-box;
      border: 1px solid #999;
    }
    
    .card-text:last-child {
      margin-bottom: 0;
    }
    
    .top-spacer {
      margin-top: 10px;
    }
    
    .note {
      font-size: small;
    }
    <form action="process.php" method="POST">
      <div class="control-group">
        <label class="control-label">Reason upload *</label>
        <div class="controls">
          <div class="form-check">
            <input type="radio" id="reasonUploadScreening" name="reasonUpload" value="screening" autocomplete="off" tabindex="0" checked>
            <label class="btn" for="reasonUploadScreening">Screening&nbsp;
                        <select id="screeningId" name="screeningId" class="field">
                            <option value="" disabled="" selected="">Select a screening</option>
                            <option value="20240328-1318">20240328-1318 John Doe (26-02-1968)</option>
                            <option value="20240328-1318">20240328-1604 [Anonymous]</option>
                            <option value="20240201-1575">20240201-1575 Jane Smith (11-11-1957)</option>
                            <option value="20240201-1100">20240201-1100 Peter Johnson (21-01-1980)</option></select>
                    </label>
            <div class="card screening top-spacer">
              <div class="card-text">
                <div class="control-group">
                  <label class="control-label">Number of images *</label>
                  <div class="controls">
                    <input type="radio" id="numberOfImages2" name="numberOfImages" value="2" autocomplete="off">
                    <label class="btn" for="numberOfImages2">Two images (Single-field)</label>
                    <input type="radio" id="numberOfImages4" name="numberOfImages" value="4" autocomplete="off">
                    <label class="btn" for="numberOfImages4">Four images (Two-field)</label>
                  </div>
                </div>
                <div class="control-group">
                  <label class="control-label">Specify images *</label>
                  <div class="controls">
                    <input type="radio" id="specImgYes" name="specImg" value="1" autocomplete="off">
                    <label class="btn" for="specImgYes">Yes</label>
                    <input type="radio" id="specImgNo" name="specImg" value="0" autocomplete="off">
                    <label class="btn" for="specImgNo">No</label>
                  </div>
                </div>
                <div class="control-group">
                  <label class="control-label">Mydriatics (dilating eye drops) used *</label>
                  <div class="controls">
                    <input type="radio" id="mydriasisYes" name="mydriasis" value="%s" autocomplete="off">
                    <label class="btn" for="mydriasisYes">Yes</label>
                    <input type="radio" id="mydriasisNo" name="mydriasis" value="%s" autocomplete="off">
                    <label class="btn" for="mydriasisNo">No</label>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="form-check">
            <input type="radio" id="reasonUploadNoSreening" name="reasonUpload" value="noScreening" autocomplete="off" tabindex="0">
            <label class="btn" for="reasonUploadNoSreening">No screening</label>
            <div class="card screening top-spacer">
              <div class="card-text">
                <span class="note">Max. 200 images. The images will be visible to all users.</span>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="control-group  top-spacer">
        <div class="controls">
          <button value="submit" name="submit">Submit</button>
        </div>
      </div>
      <p class="note top-spacer">Fields marked with * are required.</p>
    </form>

    which is expected behavior:

    When focus moves to the group in which a radio button is selected, pressing Tab and Shift+Tab keys move focus to the radio button that is checked.

    source: Can you tab through all radio buttons?