Copyright © 2026 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
本规范定义了文本及相关输入的事件扩展,以便在文本编辑器应用程序和其他处理文本输入及文本格式化的应用程序中,监控和操作默认的浏览器行为。本规范基于UI事件规范 [UI-EVENTS]。
本节描述了本文件在发布时的状态。当前 W3C 出版物列表以及本技术报告的最新修订版可在 W3C 标准与草案索引中找到。
输入事件规范 第2级 取代了输入事件的第一个版本 [INPUT-EVENTS],并包含:
本文件由 Web 编辑工作组 作为工作草案发布,使用了推荐轨道。
发布为工作草案并不意味着 W3C 及其成员的认可。
本文档为草案,可能随时被其他文档更新、替换或废弃。将本文件作为除“进行中工作”之外的引用是不合适的。
本文档由一组遵循 W3C 专利政策 的成员编写。 W3C 维护着一个 有关本小组成果的公开专利披露列表; 该页面还包括专利披露说明。任何个人若实际知晓某项专利并认为其包含 必要权利要求(Essential Claim(s)), 必须根据 W3C 专利政策第 6 节 披露相关信息。
本文件受 2025年8月18日 W3C 流程文件 的约束。
本文档描述了与编辑相关的两个事件的扩展 - input 和 beforeinput,这些事件在 UI 事件规范中进行了描述 [UI-EVENTS]。这些事件的目的是允许开发者理解和/或覆盖编辑行为的默认处理,编辑操作在执行前或执行后。
除标记为非规范性的章节外,本规范中的所有作者指南、图表、示例和注释均为非规范性内容。其他所有内容均为规范性内容。
本文档中的关键词 MAY、MUST 和 MUST NOT 应按照 BCP 14 [RFC2119] [RFC8174] 的说明进行解释,仅当这些词以如上所示全部大写形式出现时,才按上述定义解释。
此定义为非规范性内容。
杀死缓冲区 是一个与剪贴板分开的内存存储区域,用于暂存通过特定删除命令删除的富文本内容。用户可以通过表达“提取杀死缓冲区”的意图,将杀死缓冲区中的内容替换当前选中的内容。本节为非规范性内容。
创建一个基于Web的文本编辑器需要在浏览器代码之上编写大量的JavaScript,部分原因是:
本规范旨在通过提供一种简单的方法,允许Web开发者通过 beforeinput 事件覆盖浏览器对所有与文本编辑相关的用户输入的处理,并通过 input 事件监控浏览器因用户输入而对DOM的更改,从而缓解这一问题。
本节为非规范性内容。
输入事件在用户尝试编辑标记之前(beforeinput事件)和之后(input事件)发送。这包括内容的插入和删除,以及格式更改。
输入事件会在作为 编辑主机(editing hosts)
的元素上分派,包括设置了
contenteditable
属性的元素、textarea
元素,以及允许文本输入的
input
元素。
WebIDLpartial interface InputEvent {
readonly attribute DataTransfer? dataTransfer;
sequence<StaticRange> getTargetRanges();
};
partial dictionary InputEventInit {
DataTransfer? dataTransfer = null;
sequence<StaticRange> targetRanges = [];
};
属性 inputType 和 dataTransfer 属于
InputEventInit
,用于初始化相应属性,这些属性属于
InputEvent 对象。
该 targetRanges 属性属于
InputEventInit
,用于初始化 目标范围,这些范围属于
InputEvent 对象,并由
getTargetRanges() 返回。
本节为非规范性内容。
下表概述了 data 和
dataTransfer 属性何时包含
内容以及何时为
null,还概述了基于 inputType,getTargetRanges() 方法何时返回
空
Array 或非空 Array。
| 编辑主机 | inputType | data | dataTransfer | getTargetRanges() |
|---|---|---|---|---|
| Contenteditable |
"insertText",
"insertCompositionText",
"formatSetBlockTextDirection",
"formatSetInlineTextDirection",
"formatBackColor",
"formatFontColor",
"formatFontName", "insertLink"
|
Yes | null | 非空数组 |
| Contenteditable |
"insertFromPaste",
"insertFromPasteAsQuotation",
"insertFromDrop",
"insertReplacementText",
"insertFromYank"
|
null | Yes | 非空数组 |
<textarea>, <input type="text">
|
"insertText",
"insertCompositionText",
"insertFromPaste",
"insertFromPasteAsQuotation",
"insertFromDrop",
"insertReplacementText",
"insertFromYank",
"formatSetBlockTextDirection",
"formatSetInlineTextDirection",
"formatBackColor",
"formatFontColor",
"formatFontName", "insertLink"
|
Yes | null | 空数组 |
| 所有 |
"historyUndo", "historyRedo"
|
null | null | 空数组 |
| Contenteditable | 所有剩余 | null | null | 非空数组 |
<textarea>, <input type="text">
|
所有剩余 | null | null | 空数组 |
beforeinput事件是否可取消取决于inputType。
inputType的选择取决于用户的意图表达,编辑是否在IME组合过程中进行,以及选择的状态。
本规范将inputType值定义为下表中的inputType列中的值。
| inputType | 用户的意图表达 | IME组合的一部分 | beforeinput是否可取消 | 选择的状态 |
|---|---|---|---|---|
"insertText"
|
插入键入的纯文本 | 否 | 是 | 任何 |
"insertReplacementText"
|
通过拼写检查器、自动更正、书写建议或类似方式插入或替换现有内容 | 否 | 是 | 任何 |
"insertLineBreak"
|
插入换行符 | 否 | 是 | 任何 |
"insertParagraph"
|
插入段落符 | 否 | 是 | 任何 |
"insertOrderedList"
|
插入编号列表 | 否 | 是 | 任何 |
"insertUnorderedList"
|
插入项目符号列表 | 否 | 是 | 任何 |
"insertHorizontalRule"
|
插入水平线 | 否 | 是 | 任何 |
"insertFromYank"
|
用存储在kill buffer中的内容替换当前选择 | 否 | 是 | 任何 |
"insertFromDrop"
|
通过拖放插入内容 | 否 | 是 | 任何 |
"insertFromPaste"
|
从剪贴板粘贴内容或从客户端提供的图像库粘贴图像 | 否 | 是 | 任何 |
"insertFromPasteAsQuotation"
|
作为引用从剪贴板粘贴内容 | 否 | 是 | 任何 |
"insertTranspose"
|
调换最后输入的两个字素簇(grapheme cluster)的顺序。 | 否 | 是 | 任何 |
"insertCompositionText"
|
替换当前组合字符串 | 是 | 否 | 任何 |
"insertLink"
|
插入链接 | 否 | 是 | 任何 |
"deleteWordBackward"
|
删除光标位置前的单词 | 否 | 是 | 折叠 |
"deleteWordForward"
|
删除光标位置后的单词 | 否 | 是 | 折叠 |
"deleteSoftLineBackward"
|
从光标位置删除到最近的视觉换行符之前 | 否 | 是 | 折叠 |
"deleteSoftLineForward"
|
从光标位置删除到最近的视觉换行符之后 | 否 | 是 | 折叠 |
"deleteEntireSoftLine"
|
从光标位置之前的最近视觉换行符删除到光标位置之后的最近视觉换行符 | 否 | 是 | 折叠 |
"deleteHardLineBackward"
|
从光标位置删除到块元素的最近开头或
br
元素之前
|
否 | 是 | 折叠 |
"deleteHardLineForward"
|
从光标位置删除到块元素的最近结尾或
br
元素之后
|
否 | 是 | 折叠 |
"deleteByDrag"
|
通过拖动从DOM中删除内容 | 否 | 是 | 任何 |
"deleteByCut"
|
作为剪切的一部分删除当前选择 | 否 | 是 | 任何 |
"deleteContent"
|
删除选择而不指定删除的方向,并且此意图不被另一个inputType涵盖 | 否 | 是 | 未折叠 |
"deleteContentBackward"
|
删除光标位置前的内容,并且此意图不被另一个inputType涵盖,或者删除选择,选择在删除后折叠到其开始位置 | 否 | 是 | 任何 |
"deleteContentForward"
|
删除光标位置后的内容,并且此意图不被另一个inputType涵盖,或者删除选择,选择在删除后折叠到其结束位置 | 否 | 是 | 任何 |
"historyUndo"
|
撤销最后的编辑操作 | 否 | 是 | 任何 |
"historyRedo"
|
重做最后撤销的编辑操作 | 否 | 是 | 任何 |
"formatBold"
|
启动粗体文本 | 否 | 是 | 任何 |
"formatItalic"
|
启动斜体文本 | 否 | 是 | 任何 |
"formatUnderline"
|
启动下划线文本 | 否 | 是 | 任何 |
"formatStrikeThrough"
|
启动删除线文本 | 否 | 是 | 任何 |
"formatSuperscript"
|
启动上标文本 | 否 | 是 | 任何 |
"formatSubscript"
|
启动下标文本 | 否 | 是 | 任何 |
"formatJustifyFull"
|
将当前选择完全对齐 | 否 | 是 | 任何 |
"formatJustifyCenter"
|
将当前选择居中对齐 | 否 | 是 | 任何 |
"formatJustifyRight"
|
将当前选择右对齐 | 否 | 是 | 任何 |
"formatJustifyLeft"
|
将当前选择左对齐 | 否 | 是 | 任何 |
"formatIndent"
|
缩进当前选择 | 否 | 是 | 任何 |
"formatOutdent"
|
减少当前选择的缩进 | 否 | 是 | 任何 |
"formatRemove"
|
删除当前选择的所有格式 | 否 | 是 | 任何 |
"formatSetBlockTextDirection"
|
设置文本块方向 | 否 | 是 | 任何 |
"formatSetInlineTextDirection"
|
设置文本行方向 | 否 | 是 | 任何 |
"formatBackColor"
|
更改背景颜色 | 否 | 是 | 任何 |
"formatFontColor"
|
更改字体颜色 | 否 | 是 | 任何 |
"formatFontName"
|
更改字体家族 | 否 | 是 | 任何 |
inputTypes 的存在并不意味着所有实现都必须支持全部这些类型。但如果某个浏览器支持某种可能导致 DOM 发生变化的编辑操作,则它 MUST 分派 相应的
beforeinput 和 input 事件。
"deleteContentBackward"将用于用户请求在文本节点内删除文本时,以及当用户表示删除更复杂的元素或在光标位于文本节点开头时合并段落时。
"deleteContentForward"将用于用户请求在文本节点内删除文本时,以及当用户表示删除更复杂的元素或在光标位于文本节点末尾时合并段落时。
data
保存与要添加到文档中的内容相关的纯文本数据。
| inputType | 编辑主机 | data |
|---|---|---|
"insertText" 或
"insertCompositionText"
|
任意 | 要插入的纯文本字符串 |
"insertFromPaste",
"insertFromPasteAsQuotation",
"insertFromDrop",
"insertTranspose",
"insertReplacementText" 或
"insertFromYank"
|
input
或
textarea
|
要插入的纯文本字符串 |
"formatSetInlineTextDirection" 或
"formatSetBlockTextDirection"
|
任意 |
"ltr","rtl","auto"
或"null"
|
"formatBackColor" 或
"formatFontColor"
|
任意 | 包含序列化CSS组件值的字符串 [CSSOM] 用于建议的颜色 |
"formatFontName"
|
任意 | 提议的字体家族CSS属性值 |
"insertLink"
|
任意 | 提议的链接URL |
| 所有其他 | 任意 | null |
dataTransfer 属性在有相关数据时,将关于富文本和纯文本数据的信息保存在
DataTransfer
对象中,用于从文档提取或向文档添加数据。
| inputType | 编辑主机 | dataTransfer |
|---|---|---|
"insertFromPaste",
"insertFromPasteAsQuotation",
"insertFromDrop",
"insertTranspose",
"insertReplacementText" 或
"insertFromYank"
|
contenteditable
|
预先填充的 DataTransfer
对象,具体如下:
|
| 所有其他 | 任意 | null |
getTargetRanges() 返回 目标范围
,这些范围属于 InputEvent 对象。
每个 InputEvent 对象都具有
关联的 目标范围,
它是由 StaticRanges 组成的序列。当创建 InputEvent
对象时,其 目标范围 被设置为
该
targetRanges 属性的值,该属性属于 InputEventInit
字典;如果未提供该属性,则将其设置为空序列。
用户代理 必须 按如下规则设置其所分发的 目标范围,这些范围属于
受信任的 InputEvent 事件,
即其所 分发的事件,具体规则
如下:
由 目标范围 所属的 InputEvent 被 分发
时,如果是
用户代理 发起的,则 必须 仅涵盖 码点,即 用户代理 在
正常情况下会替换的码点,即使它们仅是某个 字素簇的一部分。
当 InputEvent 对象由
脚本创建时,其 目标范围 为创建该对象的脚本通过
以下
targetRanges 属性设置的值,该属性属于 InputEventInit
字典。用户
代理 不得 修改这些范围,也 不得
根据 编辑宿主、
inputType
或 DOM 的状态推导这些范围。特别是,目标
范围 所属的
InputEvent 如果不是 受信任的,则在
其
创建脚本未设置这些范围时,这些范围为空序列,即使该事件在
编辑宿主 上分发,并且
具有 inputType,
对于该属性,
用户代理 本来
会计算 目标范围。
| inputType | 编辑主机 |
getTargetRanges() 的响应
|
|---|---|---|
"historyUndo" 或 "historyRedo"
|
任意 | 空数组 |
| 其他所有 |
contenteditable
|
一个包含 StaticRanges 的数组 [DOM] 与事件相关联 |
| 其他所有 |
input
或
textarea
|
空数组 |
下表描述了 目标范围,这些范围由 用户代理
设置在其 InputEvent 对象上;这些对象由其 分发,
并作为 受信任的 事件。
对于由脚本创建的 InputEvent 对象,
其 目标范围 是
在 InputEventInit
字典中设置的范围,而不受
inputType 或
编辑宿主 的影响。
beforeinput
| 类型 |
beforeinput
|
|---|---|
| 接口 |
InputEvent
|
| 同步 / 异步 | 同步 |
| 冒泡 | 是 |
| 受信目标 |
任何作为 Element 的 编辑主机(editing
host)。
|
| 默认操作 [UI-EVENTS] |
|
|
上下文 (受信事件) |
|
用户代理(user agent) MUST 在用户尝试在 contenteditable 元素中输入时 分派 此事件。这并不一定意味着 用户代理会随即更新 DOM。
用户代理 MUST NOT 因非用户输入尝试引发的事件(如系统事件)而 分派 此事件。
这并不妨碍脚本 分发 一个
beforeinput 事件。此类事件不是 受信任的,因此其 目标范围 是在
InputEvent
对象创建时设置的范围,getTargetRanges() 会返回这些范围。
本注释不具有规范性。
第三方浏览器扩展,例如拼写或语法
检查工具,可能通过以下方式修改可编辑元素的内容:
分发合成的 beforeinput 事件
(即
其 isTrusted
属性为 false 的事件),
因为 用户
代理 不会为此类修改 分发 事件
来响应这类
修改。为了保持与这些扩展的兼容性,
建议 JavaScript 开发者监听这些
合成的 beforeinput 事件,并处理
其中 inputType
为
"insertReplacementText"、
"insertFromPaste"、"deleteContent"、
"deleteContentBackward" 或
"deleteContentForward" 的事件,并以与
相应受信任事件相同的方式处理它们。
这同样适用于使用 EditContext
编辑宿主 的编辑器:即使通常无需处理删除操作的
inputTypes "deleteContent"、
"deleteContentBackward" 和
"deleteContentForward",
因为在此类编辑宿主中,用户代理 会通过
以下机制处理这些操作:
EditContext,但编辑器仍应处理合成的
beforeinput 事件中的这些 inputTypes,
即由扩展分发的事件。同样,当第三方
扩展以类似粘贴操作的方式插入内容时,
监听合成的 beforeinput 事件,
其 inputType 为 "insertFromPaste",比
监听合成的 paste
[CLIPBOARD-APIS] 事件更可取,因为
paste 事件不
携带目标范围。
input
| 类型 | input |
|---|---|
| 接口 | InputEvent |
| 同步/异步 | 同步 |
| 冒泡 | 是 |
| 可信目标 | 任何启用了 contenteditable 属性的 Element。 |
| 默认操作 [UI-EVENTS] | 无 |
| 上下文 (可信事件) |
|
一个 user agent MUST dispatch 此事件, 应在 DOM 因用户明确表达的意图而被更新、且该意图导致的文档内容更改已由浏览器处理之后, 立即触发。如果 浏览器没有进行任何 DOM 更改,可能是因为编辑 宿主是一个 EditContext editing host(它不会自动进行 DOM 更改),或者是因为 user agent 认定不需要进行 DOM 更改,则用户代理 MUST NOT 触发此事件。
与 beforeinput 事件一样,由脚本创建的
InputEvent,如果其类型为
input,则其
目标范围 为
InputEventInit
字典中指定的范围,getTargetRanges()
将返回这些范围。
合成的开始通过调度 compositionstart 事件标记。
在合成会话期间,每当文本合成系统更新其活动文本段落时,都会调度 compositionupdate 事件。
在每个 compositionupdate
事件之后,会调度一对 beforeinput 和 input 事件。
beforeinput 和 input 事件:
inputType 属性且值为
"insertCompositionText"
data 属性等于 compositionupdate 事件的 data
targetRange 包围了合成的活动文本段落
活动文本段落的 DOM 内容在调度 beforeinput 事件后,input 事件之前更新。
合成会话的结束通过调度 compositionend 事件标记。
当调度 "insertFromPaste" beforeinput 事件时,它 必须 之前已经调度了 paste 事件。[CLIPBOARD-APIS]
本节不是规范性的。
除了现有事件(如 keydown 和
keypress [UI-EVENTS]
事件)中已存在的
浏览器指纹识别
[fingerprinting-guidance]
技术外,此功能没有已知的安全或隐私影响。
如果此功能替换现有事件,它 可能 导致可用的 指纹识别 技术减少,因为记录的是用户的意图,而不是他们使用的特定硬件类型来 表达 这个意图。
感谢:Michael Aufreiter, Adrian Bateman, Oliver Buchtala, Robin Berjon, Enrica Casucci, Bo Cupp, Domenic Denicola, Emil Eklund, Olivier Forget, Aryeh Gregor, Marijn Haverbeke, Yoshifumi Inoue, Koji Ishii, Gary Kacmarcik, Ian Kilpatrick, Frederico Caldeira Knabben, Takayoshi Kochi, Piotrek Koszuliński, Travis Leithead, Grisha Lyukshin, Miles Maxfield, Chaals McCathie Nevile, Masayuki Nakano, Ryosuke Niwa, Julie Parent, Ben Peters, Florian Rivoal, Morgan Smith, Hallvord R. M. Steen, Johan Sörlin, Cristian Talau, Dave Tapuska, Ojan Vafai, Léonie Watson, Xiaoqian Wu, Chong Zhang, Joanmarie 以及编辑任务组中的所有人为他们的意见和反馈。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: