Copyright © 2024 World Wide Web Consortium . W3C ® liability , trademark and permissive document license rules apply.
This document is a preliminary draft of a specification for the Selection API and selection related functionality. It replaces a couple of old sections of the HTML specification , the selection part of the old DOM Range specification .
This document defines APIs for selection, which allows users and authors to select a portion of a document or specify a point of interest for copy, paste, and other editing operations.
This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
This is work in progress.
This document was published by the Web Editing Working Group as an Editor's Draft.
Publication as an Editor's Draft does not imply endorsement by W3C and its Members.
This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the W3C Patent Policy . W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy .
This document is governed by the 03 November 2023 W3C Process Document .
This section is non-normative.
IE9 and Firefox 6.0a2 allow arbitrary ranges in the selection, which follows what this spec originally said. However, this leads to unpleasant corner cases that authors, implementers, and spec writers all have to deal with, and they don't make any real sense. Chrome 14 dev and Opera 11.11 aggressively normalize selections, like not letting them lie inside empty elements and things like that, but this is also viewed as a bad idea, because it takes flexibility away from authors.
So I changed the spec to a made-up compromise that allows some simplification but doesn't constrain authors much. See discussion . Basically it would throw exceptions in some places to try to stop the selection from containing a range that had a boundary point other than an Element or Text node, or a boundary point that didn't descend from a Document.
But this meant getRangeAt() had to start returning a copy, not a reference. Also, it would be prone to things failing weirdly in corner cases. Perhaps most significantly, all sorts of problems might arise when DOM mutations transpire, like if a boundary point's node is removed from its parent and the mutation rules would place the new boundary point inside a non-Text/Element node. And finally, the previously-specified behavior had the advantage of matching two major implementations, while the new behavior matched no one. So I changed it back.
See bug 15470 . IE9, Firefox 12.0a1, Chrome 17 dev, and Opera Next 12.00 alpha all make the range initially null.
Every document with a browsing context has a unique selection associated with it.
This is a requirement of the HTML spec. IE9 and Opera Next 12.00 alpha seem to follow it, while Firefox 12.0a1 and Chrome 17 dev seem not to. See Mozilla bug , WebKit bug .
This one selection must be shared by all the content of the document (though not by nested documents ), including any editing hosts in the document .
Each selection can be associated with a single range . When there is no range associated with the selection , the selection is empty . The selection must be initially empty .
A
document
's
selection
is
a
singleton
object
associated
with
that
document
,
so
it
gets
replaced
with
a
new
object
when
Document.open()
is
called.
See
bug
15470
.
IE9
and
Opera
Next
12.00
alpha
allow
the
user
to
reset
the
range
to
null
after
the
fact
by
clicking
somewhere;
Firefox
12.0a1
and
Chrome
17
dev
do
not.
We
follow
Gecko/WebKit,
because
it
lessens
the
chance
of
getRangeAt(0)
throwing.
Once a selection is associated with a given range , it must continue to be associated with that same range until this specification requires otherwise.
For
instance,
if
the
DOM
changes
in
a
way
that
changes
the
range's
boundary
points,
or
a
script
modifies
the
boundary
points
of
the
range,
the
same
range
object
must
continue
to
be
associated
with
the
selection.
However,
if
the
user
changes
the
selection
or
a
script
calls
addRange
()
,
the
selection
must
be
associated
with
a
new
range
object,
as
required
elsewhere
in
this
specification.
If the selection 's range is not null and is collapsed , then the caret position must be at that range 's boundary point . When the selection is not collapsed , this specification does not define the caret position; user agents should follow platform conventions in deciding whether the caret is at the start of the selection , the end of the selection , or somewhere else.
Each selection has a direction : forwards , backwards , or directionless . If the user creates a selection by indicating first one boundary point of the range and then the other (such as by clicking on one point and dragging to another), and the first indicated boundary point is after the second, then the corresponding selection must initially be backwards . If the first indicated boundary point is before the second, then the corresponding selection must initially be forwards . Otherwise, it must be directionless .
When
the
selection
's
range
is
mutated
by
scripts,
e.g.
via
selectNode
(
node
)
,
direction
of
the
selection
must
be
preserved.
Each selection s also have an anchor and a focus . If the selection 's range is null, its anchor and focus are both null. If the selection 's range is not null and its direction is forwards , its anchor is the range 's start , and its focus is the end . Otherwise, its focus is the start and its anchor is the end .
anchor and focus of selection need not to be in the document tree . It could be in a shadow tree of the same document .
Each document , input element, and textarea element has a boolean has scheduled selectionchange event , which is initially false.
Selection interface provides a way to interact with the selection associated with each document.
WebIDL[Exposed=Window]
interface Selection
{
readonly attribute Node? anchorNode
;
readonly attribute unsigned long anchorOffset
;
readonly attribute Node? focusNode
;
readonly attribute unsigned long focusOffset
;
readonly attribute boolean isCollapsed
;
readonly attribute unsigned long rangeCount
;
readonly attribute DOMString type
;
readonly attribute DOMString direction
;
Range getRangeAt
(unsigned long index);
undefined addRange
(Range range);
undefined removeRange
(Range range);
undefined removeAllRanges
();
undefined empty
();
sequence<StaticRange> getComposedRanges
(optional GetComposedRangesOptions
options = {});
undefined collapse
(Node? node, optional unsigned long offset = 0);
undefined setPosition
(Node? node, optional unsigned long offset = 0);
undefined collapseToStart
();
undefined collapseToEnd
();
undefined extend
(Node node, optional unsigned long offset = 0);
undefined setBaseAndExtent
(Node anchorNode, unsigned long anchorOffset, Node focusNode, unsigned long focusOffset);
undefined selectAllChildren
(Node node);
undefined modify
(optional DOMString alter, optional DOMString direction, optional DOMString granularity);
[CEReactions] undefined deleteFromDocument
();
boolean containsNode
(Node node, optional boolean allowPartialContainment = false);
stringifier
;
};
dictionary GetComposedRangesOptions
{
sequence<ShadowRoot> shadowRoots
= [];
};
anchorNode
The
attribute
must
return
the
anchor
node
of
this
,
or
null
if
the
anchor
is
null
or
anchor
is
not
in
the
document
tree
.
anchorOffset
The
attribute
must
return
the
anchor
offset
of
this
,
or
0
if
the
anchor
is
null
or
anchor
is
not
in
the
document
tree
.
focusNode
The
attribute
must
return
the
focus
node
of
this
,
or
null
if
the
focus
is
null
or
focus
is
not
in
the
document
tree
.
focusOffset
The
attribute
must
return
the
focus
offset
of
this
,
or
0
if
the
focus
is
null
or
focus
is
not
in
the
document
tree
.
isCollapsed
The attribute must return true if and only if the anchor and focus are the same (including if both are null). Otherwise it must return false.
rangeCount
The
attribute
must
return
0
if
this
is
empty
or
either
focus
or
anchor
is
not
in
the
document
tree
,
and
must
return
1
otherwise.
type
The
attribute
must
return
"None"
if
this
is
empty
or
either
focus
or
anchor
is
not
in
the
document
tree
,
"Caret"
if
this
's
range
is
collapsed
,
and
"Range"
otherwise.
direction
The
attribute
must
return
"none"
if
this
is
empty
or
this
selection
is
directionless
.
"forward"
if
this
selection's
direction
is
forwards
and
"backward"
if
this
selection's
direction
is
backwards
.
getRangeAt()
method
The
method
must
throw
an
IndexSizeError
exception
if
index
is
not
0
,
or
if
this
is
empty
or
either
focus
or
anchor
is
not
in
the
document
tree
.
Otherwise,
it
must
return
a
reference
to
(not
a
copy
of)
this
's
range
.
addRange()
method
The method must follow these steps:
rangeCount
is
not
0
,
abort
these
steps.
Since
range
is
added
by
reference,
subsequent
calls
to
getRangeAt(0)
returns
the
same
object,
and
any
changes
that
a
script
makes
to
range
after
it
is
added
must
be
reflected
in
the
selection
,
until
something
else
removes
or
replaces
this
's
range
.
In
particular,
the
selection
will
contain
b
as
opposed
to
a
after
running
the
following
code:
var
r
=
document.createRange();
r.selectNode(a);
getSelection().addRange(r);
r.selectNode(b);
removeRange()
method
The
method
must
make
this
empty
by
disassociating
its
range
if
this
's
range
is
range
.
Otherwise,
it
must
throw
a
NotFoundError
.
removeAllRanges()
method
The method must make this empty by disassociating its range if this has an associated range .
empty()
method
The
method
must
be
an
alias,
and
behave
identically,
to
removeAllRanges()
.
getComposedRanges()
method
shadowRoots
"],
repeat
these
steps:
shadowRoots
"],
repeat
these
steps:
StaticRange
whose
start
node
is
startNode
,
start
offset
is
startOffset
,
end
node
is
endNode
,
and
end
offset
is
endOffset
.
collapse()
method
The method must follow these steps:
removeAllRanges()
and
abort
these
steps.
IndexSizeError
exception
if
offset
is
longer
than
node
's
length
and
abort
these
steps.
setPosition()
method
The
method
must
be
an
alias,
and
behave
identically,
to
collapse()
.
collapseToStart()
method
The
method
must
throw
InvalidStateError
exception
if
the
this
is
empty
.
Otherwise,
it
must
create
a
new
range
,
set
the
start
both
its
start
and
end
to
the
start
of
this
's
range
,
and
then
set
this
's
range
to
the
newly-created
range
.
For collapseToStart/End, IE9 mutates the existing range, while Firefox 9.0a2 and Chrome 15 dev replace it with a new one. The spec follows the majority and replaces it with a new one, leaving the old Range object unchanged.
collapseToEnd()
method
The
method
must
throw
InvalidStateError
exception
if
the
this
is
empty
.
Otherwise,
it
must
create
a
new
range
,
set
the
start
both
its
start
and
end
to
the
end
of
this
's
range
,
and
then
set
this
's
range
to
the
newly-created
range
.
extend()
method
The method must follow these steps:
InvalidStateError
exception
and
abort
these
steps.
Reverse-engineered circa January 2011. IE doesn't support it, so I'm relying on Firefox (implemented extend() sometime before 2000) and WebKit (implemented extend() in 2007). I'm mostly ignoring Opera, because gsnedders tells me its implementation isn't compatible. Firefox 12.0a1 seems to mutate the existing range. IE9 doesn't support extend(), and it's impossible to tell whether Chrome 17 dev or Opera Next 12.00 alpha mutate or replace, because getRangeAt() returns a copy anyway. Nevertheless, I go against Gecko here, to be consistent with collapse().
setBaseAndExtent()
method
The method must follow these steps:
IndexSizeError
exception
and
abort
these
steps.
selectAllChildren()
method
The method must follow these steps:
0
).
Based mostly on Firefox 9.0a2. It has a bug that I didn't reproduce, namely that if you pass a Document as the argument, the end offset becomes 1 instead of the number of children it has. It also throws a RangeException instead of DOMException, because its implementation predated their merging.
IE9 behaves similarly but with glitches. It throws "Unspecified error." if the node is detached or display:none, and apparently in some random other cases too. It throws "Invalid argument." for detached comments (only!). Finally, if you pass it a comment, it seems to select the whole comment, unlike with text nodes.
Chrome 16 dev behaves as you'd expect given its Selection implementation. It refuses to select anything that's not visible, so it's almost always wrong. Opera 11.50 just does nothing in all my tests, as usual.
The new range replaces any existing one, doesn't mutate it. This matches IE9 and Firefox 12.0a1. (Chrome 17 dev and Opera Next 12.00 alpha can't be tested, because getRangeAt() returns a copy anyway.)
modify()
method
The method must follow these steps:
We need to more precisely define what it means to extend or move selection by each granularity.
deleteFromDocument()
method
The
method
must
invoke
deleteContents
()
on
this
's
range
if
this
is
not
empty
and
both
focus
and
anchor
are
in
the
document
tree
.
Otherwise
the
method
must
do
nothing.
This is the one method that actually mutates the range instead of replacing it. This matches IE9 and Firefox 12.0a1. (Chrome 17 dev and Opera Next 12.00 alpha can't be tested, because getRangeAt() returns a copy anyway.)
containsNode()
method
The
method
must
return
false
if
this
is
empty
or
if
node
's
root
is
not
the
document
associated
with
this
.
Otherwise,
if
allowPartialContainment
is
false
,
the
method
must
return
true
if
and
only
if
start
of
its
range
is
before
or
visually
equivalent
to
the
first
boundary
point
in
the
node
and
end
of
its
range
is
after
or
visually
equivalent
to
the
last
boundary
point
in
the
node
.
If
allowPartialContainment
is
true
,
the
method
must
return
true
if
and
only
if
start
of
its
range
is
before
or
visually
equivalent
to
the
last
boundary
point
in
the
node
and
end
of
its
range
is
after
or
visually
equivalent
to
the
first
boundary
point
in
the
node
.
stringifier
The stringification must return the string, which is the concatenation of the rendered text if there is a range associated with this .
If the selection is within a textarea or input element, it must return the selected substring in its value.
See also nsISelection.idl from Gecko. This spec doesn't have everything from there yet, in particular selectionLanguageChange() and containsNode() are missing. They are missing because I couldn't work out how to define them in terms of Ranges.
Originally, the Selection interface was a Netscape feature. The original implementation was carried on into Gecko (Firefox), and the feature was later implemented independently by other browser engines. The Netscape implementation always allowed multiple ranges in a single selection, for instance so the user could select a column of a table However, multi-range selections proved to be an unpleasant corner case that web developers didn't know about and even Gecko developers rarely handled correctly. Other browser engines never implemented the feature, and clamped selections to a single range in various incompatible fashions.
This
specification
follows
non-Gecko
engines
in
restricting
selections
to
at
most
one
range,
but
the
API
was
still
originally
designed
for
selections
with
arbitrary
numbers
of
ranges.
This
explains
oddities
like
the
coexistence
of
removeRange()
and
removeAllRanges()
,
and
a
getRangeAt()
method
that
takes
an
integer
argument
that
must
always
be
zero.
All
of
the
members
of
the
Selection
interface
are
defined
in
terms
of
operations
on
the
range
object
(if
any)
represented
by
the
object.
These
operations
can
raise
exceptions,
as
defined
for
the
Range
interface;
this
can
therefore
result
in
the
members
of
the
Selection
interface
raising
exceptions
as
well,
in
addition
to
any
explicitly
called
out
above.
This specification extends several interfaces to provide entry points to the interfaces defined in this specification.
The
Document
interface
is
defined
in
[
HTML
].
WebIDLpartial interface Document
{
Selection
? getSelection
();
};
getSelection()
method
The
method
must
return
the
selection
associated
with
this
if
this
has
an
associated
browsing
context
,
and
it
must
return
null
otherwise.
The
Window
interface
is
defined
in
[
HTML
].
WebIDLpartial interface Window
{
Selection
? getSelection
();
};
getSelection()
method
The
method
must
invoke
and
return
the
result
of
getSelection
()
on
this
's
Window
.
document
attribute.
The
GlobalEventHandlers
interface
is
defined
in
[
HTML
].
WebIDLpartial interface mixin GlobalEventHandlers
{
attribute EventHandler onselectstart
;
attribute EventHandler onselectionchange
;
};
onselectstart
The
attribute
must
be
an
event
handler
IDL
attribute
for
the
selectstart
event
supported
by
all
HTML
elements
,
Document
objects,
and
Window
objects.
onselectionchange
The
attribute
must
be
an
event
handler
IDL
attribute
for
the
selectionchange
event
supported
by
all
HTML
elements
,
Document
objects,
and
Window
objects.
When
the
user
agent
is
to
replace
data
or
substring
data
on
CharacterData
,
the
user
agent
must
update
the
range
associated
with
selection
of
the
node
document
of
the
CharacterData
as
if
it's
a
live
range
.
When
the
user
agent
is
to
split
a
Text
node
,
the
user
agent
must
update
the
range
associated
with
selection
of
the
node
document
of
the
Text
as
if
it's
a
live
range
.
When
the
user
agent
is
to
run
steps
for
normalize()
method,
the
user
agent
must
update
the
range
associated
with
selection
of
the
node
document
of
this
as
if
it's
a
live
range
.
When
the
user
agent
is
to
remove
or
,
or,
insert
,
or
move
a
node
,
the
user
agent
must
update
the
range
associated
with
selection
of
the
node
document
of
the
node
as
if
it's
a
live
range
.
,
according
to
the
Range
updating
logic
in
the
respective
algorithms.
The user agent should allow the user to change the selection associated with the active document . If the user makes any modification to a selection , the user agent must create a new range with suitable start and end of the range and associate the selection with this new range (not modify the existing range ), and set update selection 's direction to forwards if the start is before or equal to the end , backwards if if the end is before the start , or directionless if the start and the end cannot be ordered due to the platform convention.
The user agent must not make a selection empty if it was not already empty in response to any user actions (e.g. clicking on a non-editable region).
See bug 15470 . IE9 and Opera Next 12.00 alpha allow the user to reset the range to null after the fact by clicking somewhere; Firefox 12.0a1 and Chrome 17 dev do not. I follow Gecko/WebKit, because it lessens the chance of getRangeAt(0) throwing.
When
the
user
agent
is
about
to
associate
a
new
range
newRange
to
the
selection
in
response
to
a
user
initiated
action,
the
user
agent
must
fire
an
event
named
selectstart
,
which
bubbles
and
is
cancelable,
at
the
node
associated
with
the
boundary
point
of
newRange
's
start
prior
to
changing
the
selection
if
the
selection
was
previously
empty
or
the
previously
associated
range
was
collapsed
.
If the event is canceled, the user agent must not change the selection .
The user agent must not fire an event when the user agent sets the selection empty .
When the selection is dissociated with its range , associated with a new range , or the associated range 's boundary point is mutated either by the user or the content script, the user agent must schedule a selectionchange event on document .
When
an
input
or
textarea
element
provide
a
text
selection
and
its
selection
changes
(in
either
extent
or
direction
),
the
user
agent
must
schedule
a
selectionchange
event
on
the
element.
To schedule a selectionchange event on a node target , run these steps:
To fire a selectionchange event on a node target , run these steps:
selectionchange
,
which
bubbles
and
not
cancelable,
at
target
.
selectionchange
,
which
does
not
bubble
and
not
cancelable,
at
target
.
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.
There are no known security considerations for this standard.
To
mitigate
potential
privacy
risks
of
exposing
user's
use
of
assistive
technologies,
for
example,
user
agent
may
elect
to
emulate
mouse
and
keyboard
events
typically
associated
with
selectstart
or
selectionchange
events
when
the
user
opts
to
modify
the
selection
of
a
document.
Many thanks to
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: