radio.html (15924B)
1 <!DOCTYPE html> 2 <meta charset=utf-8> 3 <title>input type radio</title> 4 <link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org"> 5 <link rel=help href="https://html.spec.whatwg.org/multipage/#radio-button-state-(type=radio)"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 <div id="log"></div> 9 <input type=radio name=group1 id=radio1> 10 <input type=radio name=group1 id=radio2> 11 12 <input type=radio name=groüp2 id=radio3> 13 <input type=radio name=groüp2 id=radio4> 14 15 <input type=radio id=radio5> 16 <input type=radio id=radio6 disabled> 17 18 <input type=radio name="group5" id=radio71 checked> 19 <input type=radio name="group5" id=radio72> 20 21 <input type=radio name=group3 id=radio8 checked> 22 <input type=radio name=group3 id=radio9> 23 <input type=radio name=group4 id=radio10> 24 <input type=radio name=group4 id=radio11 checked> 25 26 <form id="testform"></form> 27 <input type=radio form=testform name=group6 id=radio12 checked> 28 <input type=radio form=testform name=group6 id=radio13> 29 <input type=radio form=testform name=group6 id=radio14> 30 31 <script> 32 var radio1 = document.getElementById('radio1'), 33 radio2 = document.getElementById('radio2'), 34 radio3 = document.getElementById('radio3'), 35 radio4 = document.getElementById('radio4'), 36 radio5 = document.getElementById('radio5'), 37 radio6 = document.getElementById('radio6'), 38 radio71 = document.getElementById('radio71'), 39 radio72 = document.getElementById('radio72'), 40 radio8 = document.getElementById('radio8'), 41 radio9 = document.getElementById('radio9'), 42 radio10 = document.getElementById('radio10'), 43 radio11 = document.getElementById('radio11'), 44 radio12 = document.getElementById('radio12'), 45 radio13 = document.getElementById('radio13'), 46 radio14 = document.getElementById('radio14'), 47 testform = document.getElementById('testform'), 48 t1 = async_test("click on mutable radio fires click event, then input event, then change event"), 49 t3 = async_test("click on non-mutable radio doesn't fire the input event"), 50 t4 = async_test("click on non-mutable radio doesn't fire the change event"), 51 t5 = async_test("canceled activation steps on unchecked radio"), 52 input_fired = false, 53 change_fired = false; 54 55 test(function(){ 56 assert_false(radio1.checked); 57 assert_false(radio2.checked); 58 radio1.checked = true; 59 assert_true(radio1.checked); 60 assert_false(radio2.checked); 61 radio2.checked = true; 62 assert_false(radio1.checked); 63 assert_true(radio2.checked); 64 }, "only one control of a radio button group can have its checkedness set to true"); 65 66 test(function(){ 67 assert_false(radio3.checked); 68 assert_false(radio4.checked); 69 radio3.checked = true; 70 assert_true(radio3.checked); 71 assert_false(radio4.checked); 72 radio4.checked = true; 73 assert_false(radio3.checked); 74 assert_true(radio4.checked); 75 }, "radio inputs with non-ASCII name attributes belong to the same radio button group"); 76 77 test(function(){ 78 assert_true(radio8.checked); 79 assert_false(radio9.checked); 80 assert_false(radio10.checked); 81 assert_true(radio11.checked); 82 radio9.name="group4"; 83 radio9.checked = true; 84 assert_true(radio8.checked); 85 assert_true(radio9.checked); 86 assert_false(radio10.checked); 87 assert_false(radio11.checked); 88 }, "changing the name of a radio input element and setting its checkedness to true makes all the other elements' checkedness in the same radio button group be set to false"); 89 90 test(function(){ 91 radio12.remove(); 92 assert_true(radio12.checked); 93 assert_false(radio13.checked); 94 assert_false(radio14.checked); 95 radio13.checked = true; 96 assert_true(radio13.checked); 97 assert_false(radio14.checked); 98 radio13.removeAttribute("form"); 99 radio14.removeAttribute("form"); 100 assert_true(radio13.checked); 101 assert_false(radio14.checked); 102 radio14.checked = true; 103 assert_false(radio13.checked); 104 assert_true(radio14.checked); 105 radio13.setAttribute("form", "testform"); 106 radio14.setAttribute("form", "testform"); 107 radio13.checked = true; 108 assert_true(radio13.checked); 109 assert_false(radio14.checked); 110 testform.remove(); 111 assert_true(radio13.checked); 112 assert_false(radio14.checked); 113 }, "moving radio input element out of or into a form should still work as expected"); 114 115 radio5.onclick = t1.step_func(function(e) { 116 click_fired = true; 117 assert_false(input_fired, "click event should fire before input event"); 118 assert_false(change_fired, "click event should fire before change event"); 119 assert_false(e.isTrusted, "click()-initiated click event shouldn't be trusted"); 120 }); 121 122 radio5.oninput = t1.step_func(function(e) { 123 input_fired = true; 124 assert_true(click_fired, "input event should fire after click event"); 125 assert_false(change_fired, "input event should fire before change event"); 126 assert_true(e.bubbles, "input event should bubble") 127 assert_true(e.isTrusted, "input event should be trusted"); 128 assert_false(e.cancelable, "input event should not be cancelable"); 129 }); 130 131 radio5.onchange = t1.step_func(function(e) { 132 change_fired = true; 133 assert_true(click_fired, "change event should fire after click event"); 134 assert_true(input_fired, "change event should fire after input event"); 135 assert_true(e.bubbles, "change event should bubble") 136 assert_true(e.isTrusted, "change event should be trusted"); 137 assert_false(e.cancelable, "change event should not be cancelable"); 138 }); 139 140 radio6.oninput= t3.step_func_done(function(e) { 141 assert_unreached("event input fired"); 142 }); 143 144 radio6.onchange = t4.step_func_done(function(e) { 145 assert_unreached("event change fired"); 146 }); 147 148 t1.step(function() { 149 radio5.click(); 150 assert_true(input_fired); 151 t1.done(); 152 }); 153 154 t3.step(function(){ 155 radio6.click(); 156 t3.done(); 157 t4.done(); 158 }); 159 160 radio72.onclick = t5.step_func_done(function(e){ 161 assert_false(radio71.checked, "click on radio should uncheck other radio in same group"); 162 assert_true(radio72.checked, "click on radio should check that radio"); 163 e.preventDefault(); 164 // The cancelation of the click doesn't have an effect until after all the click event handlers have been run. 165 assert_false(radio71.checked, "radio remains unchecked immediately after click event on other radio in same group is canceled"); 166 assert_true(radio72.checked, "clicked radio remains checked immediately after click event is canceled"); 167 }); 168 169 t5.step(function(){ 170 assert_true(radio71.checked, "initially checked radio should be checked"); 171 assert_false(radio72.checked, "other radios in same group as initially-checked radio should be unchecked"); 172 radio72.click(); 173 // Now that the click event has been fully dispatched, its cancelation has taken effect. 174 assert_true(radio71.checked, "canceled click event on radio should leave the previously-checked radio checked"); 175 assert_false(radio72.checked, "canceled click event on previously-unchecked radio should leave that radio unchecked"); 176 }); 177 178 test(() => { 179 const container = document.createElement('div'); 180 container.innerHTML = 181 '<input type=radio name=n1><span><input type=radio name=n1 checked></span>' + 182 '<form><input type=radio name=n1 checked></form>'; 183 const radios = container.querySelectorAll('input'); 184 assert_false(radios[0].checked, 'Sanity check: The first radio should be unchecked'); 185 assert_true(radios[1].checked, 'Sanity check: The second radio should be checked'); 186 assert_true(radios[2].checked, 'Sanity check: The third radio should be checked'); 187 188 radios[0].checked = true; 189 assert_true(radios[0].checked, 'The first radio should be checked after setting checked'); 190 assert_false(radios[1].checked, 'The second radio should be unchecked after setting checked'); 191 assert_true(radios[2].checked, 'The third radio should be checked after setting checked'); 192 193 radios[1].required = true; 194 assert_false(radios[0].validity.valueMissing, 'The first radio should be valid'); 195 assert_false(radios[1].validity.valueMissing, 'The second radio should be valid'); 196 assert_false(radios[2].validity.valueMissing, 'The third radio should be valid'); 197 198 radios[0].remove(); 199 assert_false(radios[0].validity.valueMissing, 'The first radio should be valid because of no required'); 200 assert_true(radios[1].validity.valueMissing, 'The second radio should be invalid***'); 201 assert_false(radios[2].validity.valueMissing, 'The third radio should be valid'); 202 203 radios[0].required = true; 204 radios[0].checked = false; 205 assert_true(radios[0].validity.valueMissing, 'The first radio should be invalid because of required'); 206 }, 'Radio buttons in an orphan tree should make a group'); 207 208 test(() => { 209 const container = document.createElement('div'); 210 container.innerHTML = 211 '<form>' + 212 '<input type=radio name=group1 id=radio1 checked>' + 213 '<input type=radio name=group1 id=radio2>' + 214 '</form>' + 215 '<form>' + 216 '<input type=radio name=group1 id=radio3 checked>' + 217 '<input type=radio name=group1 id=radio4>' + 218 '</form>' + 219 '<input type=radio name=group1 id=radio5 checked>' + 220 '<input type=radio name=group1 id=radio6>'; 221 const radio1 = container.querySelector('#radio1'); 222 const radio2 = container.querySelector('#radio2'); 223 const radio3 = container.querySelector('#radio3'); 224 const radio4 = container.querySelector('#radio4'); 225 const radio5 = container.querySelector('#radio5'); 226 const radio6 = container.querySelector('#radio6'); 227 228 // initial conditions 229 assert_true(radio1.checked, 'radio1 should be checked'); 230 assert_false(radio2.checked, 'radio2 should be unchecked'); 231 assert_true(radio3.checked, 'radio3 should be checked'); 232 assert_false(radio4.checked, 'radio4 should be unchecked'); 233 assert_true(radio5.checked, 'radio5 should be checked'); 234 assert_false(radio6.checked, 'radio6 should be unchecked'); 235 236 radio2.checked = true; 237 assert_false(radio1.checked, 'radio1 should be unchecked'); 238 assert_true(radio2.checked, 'radio2 should be checked'); 239 assert_true(radio3.checked, 'radio3 should remain checked'); 240 assert_true(radio5.checked, 'radio5 should remain checked'); 241 242 radio4.checked = true; 243 assert_false(radio1.checked, 'radio1 should remain unchecked'); 244 assert_true(radio2.checked, 'radio2 should remain checked'); 245 assert_false(radio3.checked, 'radio3 should be unchecked'); 246 assert_true(radio4.checked, 'radio4 should be checked'); 247 assert_true(radio5.checked, 'radio5 should remain checked'); 248 249 radio6.checked = true; 250 assert_false(radio1.checked, 'radio1 should remain unchecked'); 251 assert_true(radio2.checked, 'radio2 should remain checked'); 252 assert_false(radio3.checked, 'radio3 should remain unchecked'); 253 assert_true(radio4.checked, 'radio4 should remain checked'); 254 assert_false(radio5.checked, 'radio5 should be unchecked'); 255 assert_true(radio6.checked, 'radio6 should be checked'); 256 }, "Radio buttons in different groups (because they have different form owners or no form owner) do not affect each other's checkedness"); 257 258 test(() => { 259 const container = document.createElement('div'); 260 container.innerHTML = 261 '<form>' + 262 '<input type=radio name=group1 id=radio1 checked>' + 263 '<input type=radio name=group1 id=radio2>' + 264 '<input type=radio name=group1 id=radio3>' + 265 '<input type=radio name=group1 id=radio4>' + 266 '</form>'; 267 const radio1 = container.querySelector('#radio1'); 268 const radio2 = container.querySelector('#radio2'); 269 const radio3 = container.querySelector('#radio3'); 270 const radio4 = container.querySelector('#radio4'); 271 272 // initial conditions 273 assert_true(radio1.checked, 'radio1 should be checked'); 274 assert_false(radio2.checked, 'radio2 should be unchecked'); 275 assert_false(radio3.checked, 'radio3 should be unchecked'); 276 assert_false(radio4.checked, 'radio4 should be unchecked'); 277 278 radio3.remove(); 279 radio4.remove(); 280 radio3.checked = true; 281 radio4.checked = true; 282 assert_true(radio1.checked, 'radio1 should remain checked'); 283 assert_false(radio2.checked, 'radio2 should remain unchecked'); 284 assert_true(radio3.checked, 'radio3 should be checked'); 285 assert_true(radio4.checked, 'radio4 should be checked'); 286 }, "Radio buttons in different groups (because they are not in the same tree) do not affect each other's checkedness"); 287 288 test(() => { 289 const container = document.createElement('div'); 290 container.innerHTML = 291 '<form>' + 292 '<input type=radio name=group1 id=radio1 checked>' + 293 '<input type=radio name=group1 id=radio2>' + 294 '<input type=radio name=group2 id=radio3 checked>' + 295 '<input type=radio name=group2 id=radio4>' + 296 '<input type=radio name="" id=radio5 checked>' + 297 '<input type=radio name="" id=radio6>' + 298 '<input type=radio id=radio7 checked>' + 299 '<input type=radio id=radio8>' + 300 '</form>'; 301 const radio1 = container.querySelector('#radio1'); 302 const radio2 = container.querySelector('#radio2'); 303 const radio3 = container.querySelector('#radio3'); 304 const radio4 = container.querySelector('#radio4'); 305 const radio5 = container.querySelector('#radio5'); 306 const radio6 = container.querySelector('#radio6'); 307 const radio7 = container.querySelector('#radio7'); 308 const radio8 = container.querySelector('#radio8'); 309 310 // initial conditions 311 assert_true(radio1.checked, 'radio1 should be checked'); 312 assert_false(radio2.checked, 'radio2 should be unchecked'); 313 assert_true(radio3.checked, 'radio3 should be checked'); 314 assert_false(radio4.checked, 'radio4 should be unchecked'); 315 assert_true(radio5.checked, 'radio5 should be checked'); 316 assert_false(radio6.checked, 'radio6 should be unchecked'); 317 assert_true(radio7.checked, 'radio7 should be checked'); 318 assert_false(radio8.checked, 'radio8 should be unchecked'); 319 320 radio2.checked = true; 321 assert_false(radio1.checked, 'radio1 should be unchecked'); 322 assert_true(radio2.checked, 'radio2 should be checked'); 323 assert_true(radio3.checked, 'radio3 should remain checked'); 324 assert_false(radio4.checked, 'radio4 should remain unchecked'); 325 assert_true(radio5.checked, 'radio5 should remain checked'); 326 assert_false(radio6.checked, 'radio6 should remain unchecked'); 327 assert_true(radio7.checked, 'radio7 should remain checked'); 328 assert_false(radio8.checked, 'radio8 should remain unchecked'); 329 330 radio6.checked = true; 331 assert_false(radio1.checked, 'radio1 should remain unchecked'); 332 assert_true(radio2.checked, 'radio2 should remain checked'); 333 assert_true(radio3.checked, 'radio3 should remain checked'); 334 assert_false(radio4.checked, 'radio4 should remain unchecked'); 335 assert_true(radio5.checked, 'radio5 should remain checked'); 336 assert_true(radio6.checked, 'radio6 should be checked'); 337 assert_true(radio7.checked, 'radio7 should remain checked'); 338 339 radio8.checked = true; 340 assert_false(radio1.checked, 'radio1 should remain unchecked'); 341 assert_true(radio2.checked, 'radio2 should remain checked'); 342 assert_true(radio3.checked, 'radio3 should remain checked'); 343 assert_false(radio4.checked, 'radio4 should remain unchecked'); 344 assert_true(radio5.checked, 'radio5 should remain checked'); 345 assert_true(radio6.checked, 'radio6 should remain checked'); 346 assert_true(radio7.checked, 'radio7 should remain checked'); 347 assert_true(radio8.checked, 'radio8 should be checked'); 348 349 }, "Radio buttons in different groups (because they have different name attribute values, or no name attribute) do not affect each other's checkedness"); 350 351 </script>