跳转到内容

PasswordInput 密码输入

一格密码框,带明暗切换按钮,并在大写锁定开启时给出提示。

用法

root 持有状态,control 是视觉盒;不传 value 与 revealed 即为非受控,明暗由组件自行管理,按钮中的图标随明暗切换

组件结构

加粗的是必需部件。

data-scope="password-input"root · label · control · input · visibility-trigger · caps-lock-indicator · strength-meter

示例

受控

值与明暗都可受控:传入后由宿主决定,组件只报告意图,是否写回由宿主决定

当前:•••••••

大写锁定提示

打开大写锁定后在框中输入一个字符:提示显示,读屏也会朗读一次;焦点离开输入框即消失

禁用与校验态

disabled 连明暗切换一起停止,read-only 只锁定值、明暗照常切换,invalid 只标注不拦截输入

变体

variant 决定底色与描边的绘制方式:描边、淡色填底、无框;密码框没有实心档

颜色

tone 决定使用哪族颜色,与 variant 正交;这里固定 subtle 形态,语气的底色差别不必聚焦即可看到

尺寸

size 只改变高度、内边距与字号,标签、切换按钮与大写锁定提示一起换档;不写即默认档

注册表单

提供 name 后才参与提交,auto-complete 写为 new-password 密码管理器才会保存新密码而不是填入旧密码

设计指引

何时使用

  • 登录、注册、修改密码等需要遮蔽输入内容的字段。
  • 用户需要核对输入:切换为明文查看,再切回。

何时不用

  • 只需要遮蔽输入、不需要明暗切换与大写锁定提示时,使用文本字段type="password",结构更少。
  • 输入短验证码或一次性密码时,使用分格输入
  • 需要比较两次输入是否一致时,属于表单校验,交给表单表单字段

特性

  • 明暗切换在 revealed / defaultRevealed 两态齐全,受控与非受控走同一条路径。
  • 切换之后焦点留在切换按钮上,框内的光标与选中范围原样恢复。
  • 大写锁定提示由按键事件驱动,焦点离开输入框即熄灭。
  • autoComplete 默认 current-password,注册表单应显式改为 new-password
  • strength 传入 0–4 五档即显示强度条;评分算法由调用方负责,组件只绘制档位。
  • 形态、语气、尺寸三轴与文本字段同源,并排放置不会相差一档。
  • 一体式 control 投影 Field Chrome 家族,描边式静息、无影,聚焦描边一律 --xh-border-control-focus;显隐动作走 Action Control 的 field-inset ghost 档(正方视觉盒、inset 圆角、悬停 100 / 按下 200 中性底与 0.97 按压),与输入 / 状态区之间有半高语义分隔,三档尺寸和 compact 密度使用同一比例。
  • 自动填充由家族用 canvas 实体底与默认前景重绘,避免浏览器注入的颜色把框切成异色段。

组合

  • 外层放表单字段获取标签、说明与错误文本。
  • 切换按钮留空时由皮肤按 data-state 绘制显示或隐藏图标。需要品牌图标时可放入图标替换内置字形,组件仍负责切换按钮的可访问名称。

最佳实践

  • 自行编写角色节点时(Web Components 用法),三个角色必须使用对应标签:标题是原生 <label>、输入框是原生 <input>、切换按钮是原生 <button>。标题的 for 始终指向输入框的 id,写成 <span> 则无法点击;切换按钮写成 <div> 则没有 Enter / Space 激活;两种情况都不报错,只是静默失效。
  • 大写锁定提示节点也由作者写出(元素不生成结构),写成空壳即可,文字由组件填充。Vue 侧由组件代劳。
  • 明文只在用户主动切换时出现,不默认 defaultRevealed
  • 切换按钮在切换后不消失、不换位置:它持有焦点,移动会让键盘用户丢失位置。
  • readOnly 只禁止改值,不禁止显隐:用户仍可聚焦、复制和核对已有密码;disabled 才同时禁用输入与显隐动作。
  • 大写锁定提示只提示,不拦截提交:它是键盘的物理状态,用户可能确实需要输入大写。
  • 注册表单把 autoComplete 写成 new-password,否则密码管理器会填入旧密码。

当前边界

  • anatomy 尚无正式的 prefix / suffix 部件;control 中的作者节点目前只按统一 gap 排布,不承诺前后缀语义或专门状态。需要时应以独立三端部件提交,不用 CSS 推断任意子节点的职责。
  • control 在 meta 中仍是可选部件,但共享 Field Chrome、组合焦点环与动作分隔都以它为边界;无 control 的结构只是独立输入框和按钮,不再绘制独立外壳。是否将其提升为必需部件属于后续公共结构合同变更。

反模式

  • 用它接收“请再输入一次”的确认格却不提供独立标签:读屏读出的两格完全相同。
  • 把明暗状态存入接口或本地存储:下次打开页面时密码是明文。

API 参考

产物

自定义元素<xh-password-input>
Vue 组件XhPasswordInputCapsLockIndicator XhPasswordInputControl XhPasswordInputInput XhPasswordInputLabel XhPasswordInputRoot XhPasswordInputStrengthMeter XhPasswordInputVisibilityTrigger
组合式函数usePasswordInput
状态机passwordInputMachine
皮肤@xihan-ui/styles/password-input.css

Props

属性类型必填说明
valuestring受控值;提供后由宿主决定,状态机不自行修改。
defaultValuestring非受控初值。
revealedboolean受控的显隐态:明文是否显示;提供后由宿主决定。
defaultRevealedboolean非受控的初始显隐态,默认隐藏。
disabledboolean
readOnlyboolean
requiredboolean
invalidboolean
namestring表单字段名;提供后才参与提交。
placeholderstring
autoCompletestring写到 input 上的 autocomplete,默认 current-password。 密码管理器据此决定该字段是填入旧密码还是保存新密码,注册表单要显式写 new-password。
strengthnumber强度档位,0 到 4 共五档。提供后才显示强度条,默认不显示。 打分算法归调用方:口令强弱是产品规则(字典、泄漏库、业务口径),组件只负责绘制档位。 超出区间的值被夹回区间。
translationsPartial<PasswordInputTranslations>读屏文案覆盖;未提供的条目使用组件内建英文。
variantControlVariant形态:outline / subtle / ghost,决定底色与描边的绘制方式。默认 outline。
toneTone语气:brand / neutral / success / warning / danger / info,决定使用哪族颜色。
sizeSize尺寸:sm / md / lg。
onValueChange(details: PasswordInputValueChangeDetails) => void
onRevealedChange(details: PasswordInputRevealedChangeDetails) => void

事件

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
value-changePasswordInputValueChangeDetails值变化;detail 为 { value: string }
revealed-changePasswordInputRevealedChangeDetails显隐变化;detail 为 { revealed: boolean }

插槽

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhPasswordInputRootdefaultPasswordInputRootSlotProps

状态

公开状态写入 data-state

部件取值
visibility-trigger'visible' | 'hidden'
caps-lock-indicator'visible' | 'hidden'

以下名称仅用于内部状态机。

状态idle

事件VALUE.SET · REVEALED.SET · REVEALED.TOGGLE · CAPS_LOCK.SET · FORM.RESET · PRESS.START · PRESS.END

判据canEdit · canReveal

connect API

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
valuestring
emptyboolean值为空串。
revealedboolean当前明文是否已显示。
capsLockboolean大写锁定是否开启;为真时提示部件才显示。
disabledboolean
readOnlyboolean
invalidboolean
inputTypePasswordInputType输入框当前的 type,随 revealed 变化。
capsLockMessagestring大写锁定播报区当前的文字:开启时是 translations.capsLockOn,关闭时是空串。 适配器把它写为提示部件的文本内容,读屏朗读的即这一段。
strengthnumber | undefined夹回 0–4 后的强度档位;未提供 strength 时为 undefined,此时强度条收起。
setValue(next: string) => void直接写值,只受 disabled / readOnly 约束。
setRevealed(next: boolean) => void指定显隐态;整个控件禁用时不生效。
toggleRevealed() => void切换显隐态;整个控件禁用时不生效。
getRootProps() => T['element']
getLabelProps() => T['label']
getControlProps() => T['element']
getInputProps() => T['input']
getVisibilityTriggerProps() => T['button']
getCapsLockIndicatorProps() => T['element']
getStrengthMeterProps() => T['element']强度条:档位写在 data-level 与 aria-valuenow 上;未提供 strength 时带 hidden 收起。

无障碍

键盘

规格出处:W3C APG

按键生效条件行为
Enter / Spacefocus on visibility-trigger, 控件未禁用切换明暗;切换按钮是原生 button,这两个键由平台转换为 click。焦点留在按钮上,输入框中的光标与选中范围原样恢复
CapsLockfocus in input每次按键都重读一次大写锁定状态:开着就亮起提示,焦点离开输入框即熄灭
Enter / Spaceheld on visibility-trigger, 控件未禁用按住期间切换按钮投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下,按住途中明暗翻面不影响按压面。只读不拦明暗,按压面也照常给

ARIA

以下属性由 connect 生成。

部件属性
inputaria-describedbycapsLock 部件的 id | undefined
inputaria-invalid'true' | 'false'
inputaria-labelledbylabel 部件的 id
visibility-triggeraria-controlspassword-input-input 部件的 id
visibility-triggeraria-labellabel.visibilityTriggerHide | label.visibilityTriggerShow
caps-lock-indicatoraria-atomic'true'
caps-lock-indicatoraria-live'polite'
caps-lock-indicatorrole'status'
strength-meteraria-labellabel.strengthMeter
strength-meteraria-valuemax4
strength-meteraria-valuemin0
strength-meteraria-valuenowundefined | Math.min(Math.max(Math.trunc(rawStrength), 0), STRENG…
strength-meterrole'meter'
  • 切换按钮的名称随状态变化:隐藏时为“显示密码”,显示时为“隐藏密码”,两句都来自 translations。名称已经说明当前状态,因此不再叠加 aria-pressed,避免读出“隐藏密码 已按下”这类混淆信息。
  • 切换按钮的 aria-controls 指向输入框,读屏可以跳到被切换的输入框。
  • 大写锁定提示是 role="status" 的活动区域,节点始终在场、始终渲染,开与关只替换区内文字。活动区域播报的是内容变化,区域本身被 hiddendisplay: none 撤下再出现时,读屏会视为插入新节点而多数不读,因此该区域不按需挂载,也不依赖显隐触发播报。
  • 提示区的文字来自 translations.capsLockOn,由组件写入节点,作者把该节点留空即可;需要图标时在该部件上挂 ::before
  • 焦点晚于提示出现的用户,通过输入框的 aria-describedby 也能听到同一句。
  • 输入框始终带 spellcheck="false" / autocapitalize="off" / autocorrect="off":切换为明文时它就是普通文本框,拼写检查会把内容发送到远端服务,移动端还会自动大写首字母并按词典纠错。

样式参考

皮肤

@xihan-ui/styles/password-input.css 使用 [data-scope="password-input"][data-part="root"] 部件选择器,位于 xihan.components 层。覆盖样式使用 xihan.overrides

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性

connect 生成;条件不成立时不输出无值属性。

部件属性
rootdata-disabled''(条件成立时才出现)
rootdata-empty''(条件成立时才出现)
rootdata-invalid''(条件成立时才出现)
rootdata-readonly''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-toneprops.tone
rootdata-variantprops.variant
labeldata-disabled''(条件成立时才出现)
controldata-disabled''(条件成立时才出现)
controldata-invalid''(条件成立时才出现)
controldata-readonly''(条件成立时才出现)
controldata-variantprops.variant
controldata-xh-field-chrome''
controldata-xh-field-sizeprops.size
inputdata-disabled''(条件成立时才出现)
inputdata-invalid''(条件成立时才出现)
inputdata-readonly''(条件成立时才出现)
inputdata-xh-field-input''
inputdata-xh-field-layout'single-line'
visibility-triggerdata-disabled''(条件成立时才出现)
visibility-triggerdata-pressed''(条件成立时才出现)
visibility-triggerdata-state'visible' | 'hidden'
visibility-triggerdata-xh-action-control''
visibility-triggerdata-xh-action-display'always'
visibility-triggerdata-xh-action-profile'field-inset'
visibility-triggerdata-xh-action-sizeprops.size
visibility-triggerdata-xh-action-variant'ghost'
caps-lock-indicatordata-state'visible' | 'hidden'
strength-meterdata-disabled''(条件成立时才出现)
strength-meterdata-levelundefined | String(strength)

CSS 变量

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-password-input-caps-lock-fgcaps-lock-indicatorcolordefault--xh-fg-mutedpassword-input 的 caps-lock-indicator 部件 color 覆盖槽。
--xh-password-input-caps-lock-fg-disabledcaps-lock-indicator
control
colordisabled--xh-fg-disabledpassword-input 的 caps-lock-indicator、control 部件 color 覆盖槽。
--xh-password-input-caps-lock-font-sizecaps-lock-indicatorfont-sizedefault--xh-_password-input-caps-lock-font-sizepassword-input 的 caps-lock-indicator 部件 font-size 覆盖槽。
--xh-password-input-control-bgcontrolbackground-colorxh-field-chrome--xh-_field-variant-bg-restpassword-input 的 control 部件 background-color 覆盖槽。
--xh-password-input-control-bg-disabledcontrolbackground-colordisabled
xh-field-chrome
--xh-_field-variant-bg-disabledpassword-input 的 control 部件 background-color 覆盖槽。
--xh-password-input-control-bg-hovercontrolbackground-colordisabled
hover
invalid
loading
not([data-disabled])
not([data-invalid])
not([data-loading])
not([data-readonly])
readonly
xh-field-chrome
--xh-_field-variant-bg-hoverpassword-input 的 control 部件 background-color 覆盖槽。
--xh-password-input-control-bg-readonlycontrolbackground-colorreadonly
xh-field-chrome
--xh-_field-variant-bg-read-onlypassword-input 的 control 部件 background-color 覆盖槽。
--xh-password-input-control-bordercontrolborderxh-field-chrome--xh-_field-variant-border-restpassword-input 的 control 部件 border 覆盖槽。
--xh-password-input-control-border-focuscontrolborder-colordisabled
focus-within
not([data-disabled])
xh-field-chrome
--xh-_field-variant-border-focuspassword-input 的 control 部件 border-color 覆盖槽。
--xh-password-input-control-border-hovercontrolborder-colordisabled
hover
invalid
loading
not([data-disabled])
not([data-invalid])
not([data-loading])
not([data-readonly])
readonly
xh-field-chrome
--xh-_field-variant-border-hoverpassword-input 的 control 部件 border-color 覆盖槽。
--xh-password-input-control-border-invalidcontrolborder-colorinvalid
xh-field-chrome
--xh-_field-variant-border-invalidpassword-input 的 control 部件 border-color 覆盖槽。
--xh-password-input-control-fgcontrolcolorxh-field-chrome--xh-fg-defaultpassword-input 的 control 部件 color 覆盖槽。
--xh-password-input-control-gapcontrolgapxh-field-chrome--xh-_password-input-gappassword-input 的 control 部件 gap 覆盖槽。
--xh-password-input-control-hcontrolblock-size
min-block-size
has([data-xh-field-input][data-xh-field-layout='multi-tag'])
has([data-xh-field-input][data-xh-field-layout='single-line'])
has([data-xh-field-input][data-xh-field-layout='textarea'])
xh-field-chrome
xh-field-input
xh-field-layout=multi-tag
xh-field-layout=single-line
xh-field-layout=textarea
--xh-_password-input-hpassword-input 的 control 部件 block-size、min-block-size 覆盖槽。
--xh-password-input-control-min-wcontrol
root
min-inline-sizedefault
xh-field-chrome
--xh-control-min-wpassword-input 的 control、root 部件 min-inline-size 覆盖槽。
--xh-password-input-control-pxcontrolpadding-inlinexh-field-chrome--xh-_password-input-pxpassword-input 的 control 部件 padding-inline 覆盖槽。
--xh-password-input-control-radiuscontrolborder-radiusxh-field-chrome--xh-shape-controlpassword-input 的 control 部件 border-radius 覆盖槽。
--xh-password-input-control-shadowcontrolbox-shadowxh-field-chromenonepassword-input 的 control 部件 box-shadow 覆盖槽。
--xh-password-input-control-wrootinline-size
min-inline-size
default--xh-control-wpassword-input 的 root 部件 inline-size、min-inline-size 覆盖槽。
--xh-password-input-gaprootgapdefault--xh-space-1password-input 的 root 部件 gap 覆盖槽。
--xh-password-input-icon-sizecontrol
root
--xh-icon-sizedefault
size=lg
size=sm
xh-field-chrome
--xh-_field-size-glyph-size
--xh-glyph-size-lg
--xh-glyph-size-md
--xh-glyph-size-sm
password-input 的 control、root 部件 --xh-icon-size 覆盖槽。
--xh-password-input-input-autofill-bginputbox-shadow-webkit-autofill
autofill
xh-field-input
--xh-bg-canvaspassword-input 的 input 部件 box-shadow 覆盖槽。
--xh-password-input-input-autofill-fginput-webkit-text-fill-color-webkit-autofill
autofill
xh-field-input
--xh-fg-defaultpassword-input 的 input 部件 -webkit-text-fill-color 覆盖槽。
--xh-password-input-input-fginputcolorxh-field-input--xh-fg-defaultpassword-input 的 input 部件 color 覆盖槽。
--xh-password-input-input-font-sizeinputfont-sizexh-field-input--xh-_password-input-font-sizepassword-input 的 input 部件 font-size 覆盖槽。
--xh-password-input-label-fglabelcolordefault--xh-fg-defaultpassword-input 的 label 部件 color 覆盖槽。
--xh-password-input-label-fg-disabledlabelcolordisabled--xh-fg-subtlepassword-input 的 label 部件 color 覆盖槽。
--xh-password-input-label-font-sizelabelfont-sizedefault--xh-text-label-sizepassword-input 的 label 部件 font-size 覆盖槽。
--xh-password-input-label-font-weightlabelfont-weightdefault--xh-text-label-weightpassword-input 的 label 部件 font-weight 覆盖槽。
--xh-password-input-placeholder-fginputcolorplaceholder
xh-field-input
--xh-fg-subtlepassword-input 的 input 部件 color 覆盖槽。
--xh-password-input-strength-fgstrength-meterbackgroundempty--xh-_password-input-strength-fgpassword-input 的 strength-meter 部件 background 覆盖槽。
--xh-password-input-strength-radiusstrength-meterborder-radiusdefault--xh-shape-pillpassword-input 的 strength-meter 部件 border-radius 覆盖槽。
--xh-password-input-strength-thicknessstrength-meterblock-sizedefault--xh-track-thicknesspassword-input 的 strength-meter 部件 block-size 覆盖槽。
--xh-password-input-strength-trackstrength-meterbackgrounddefault--xh-bg-subtle-activepassword-input 的 strength-meter 部件 background 覆盖槽。
--xh-password-input-trigger-bgvisibility-triggerbackground-colordefault--xh-_action-variant-bg-restpassword-input 的 visibility-trigger 部件 background-color 覆盖槽。
--xh-password-input-trigger-bg-activevisibility-triggerbackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedpassword-input 的 visibility-trigger 部件 background-color 覆盖槽。
--xh-password-input-trigger-bg-hovervisibility-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hoverpassword-input 的 visibility-trigger 部件 background-color 覆盖槽。
--xh-password-input-trigger-fgvisibility-triggercolordefault--xh-fg-mutedpassword-input 的 visibility-trigger 部件 color 覆盖槽。
--xh-password-input-trigger-fg-hovervisibility-triggercolordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-fg-defaultpassword-input 的 visibility-trigger 部件 color 覆盖槽。
--xh-password-input-trigger-font-sizevisibility-triggerfont-sizedefault--xh-_password-input-trigger-font-sizepassword-input 的 visibility-trigger 部件 font-size 覆盖槽。
--xh-password-input-trigger-radiusvisibility-triggerborder-radiusdefault--xh-shape-insetpassword-input 的 visibility-trigger 部件 border-radius 覆盖槽。
--xh-password-input-trigger-sizevisibility-triggerblock-size
inline-size
min-inline-size
default
xh-action-profile=field-inset
--xh-_action-profile-visual-sizepassword-input 的 visibility-trigger 部件 block-size、inline-size、min-inline-size 覆盖槽。
--xh-password-input-visibility-trigger-separator-colorcontrol
input
visibility-trigger
background-imagehas(~ [data-scope='password-input'][data-part='input'])--xh-border-subtlepassword-input 的 control、input、visibility-trigger 部件 background-image 覆盖槽。
--xh-password-input-visibility-trigger-separator-hcontrol
input
visibility-trigger
background-sizehas(~ [data-scope='password-input'][data-part='input'])--xh-_password-input-divider-hpassword-input 的 control、input、visibility-trigger 部件 background-size 覆盖槽。

动效

本组件皮肤不含过渡与关键帧,也没有脚本驱动的动效:状态一变,外观立即到位。

RTL

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;另有按 dir 分支的规则。

Released under The MIT License