required仅在表单提交时校验,不阻止用户清空字段;readonly对checkbox/radio/hidden/select无效;两者可共存但需语义自洽;js控制应优先用setattribute;前后端均需校验。

required 属性只在表单提交时起作用,不阻止用户清空字段
required 不是实时拦截器。它只在 form.submit() 或点击 type="submit" 按钮触发原生校验时生效,用户随时能手动删掉内容、粘贴空格、甚至用 JS 清空 value——这些操作都不会立刻报错。
- 浏览器会在提交前检查
value.trim() === "",若为真则聚焦该字段并显示默认提示(如“请填写此字段”) - 对
type="checkbox"或type="radio",校验逻辑不同:前者看是否勾选,后者看同名组是否有任意一项被选中 -
required对type="hidden"无效——隐藏域即使为空也不会触发校验,因为它的设计本就不参与用户输入流程 - 如果字段有
placeholder但没填值,required仍会失败;placeholder 不是 value,也不影响校验结果
readonly 属性对 type="text" 类有效,对 checkbox/radio/hidden 完全忽略
浏览器只在特定 type 上响应 readonly:包括 text、password、email、tel、url、search、date、number、datetime-local 和 textarea。其他类型加了也白加。
-
<input type="checkbox" readonly>→ 浏览器直接无视,复选框照常可点 -
<input type="hidden" readonly>→ 无视觉或行为变化,因为 hidden 本就不渲染交互界面 -
<select readonly></select>→ 不生效,select没有 readonly 支持,得用disabled或 JS 封装控制 - 移动端 WebView(如某些 Android 旧内核)可能对
datetime-local的 readonly 支持不稳定,建议降级为text+ 格式化约束
required 和 readonly 同时存在时,互不干扰但语义需自洽
两者可以共存,但组合使用容易暴露逻辑矛盾:比如一个字段既要求用户必须填,又禁止用户编辑——这在 UX 上不合理,后端也收不到真实值(因为 readonly 字段的 value 是预设的,用户无法改,但 required 又强制它不能为空)。
- 典型误用:
<input type="text" value="AUTO-2026-001" required readonly>→ 表单能提交,但 value 固定,用户无法覆盖,此时 required 实际形同虚设 - 合理场景:动态生成订单号后锁定(
readonly),同时该字段是业务必传项(required),后端依赖它做幂等校验 - 注意 Safari 对
required+readonly的 focus 行为有差异:提交失败时,Safari 可能无法自动聚焦到 readonly 字段,导致用户看不到错误提示
JS 动态控制 required/readonly 时,DOM 属性比 JS 属性更可靠
用 JavaScript 切换状态时,别依赖 element.required = false 或 element.readOnly = false —— 特别是在 Safari 15 及更早版本中,readOnly 的布尔赋值经常失效。
- 设为必填:
element.setAttribute("required", "required");取消必填:element.removeAttribute("required") - 设为只读:
element.setAttribute("readonly", "readonly");解除只读:element.removeAttribute("readonly") - React 中必须写
required={isRequired}和readOnly={isReadonly}(驼峰命名,且是布尔 prop) - Vue 中绑定
:required="isRequired"和:readonly="isReadonly"可行,但注意 Vue 2 对 boolean attribute 的处理逻辑:值为false时不会移除属性,需显式v-bind:readonly="null"或用v-bind绑定完整表达式











