Copyright © 2019 W3C ® ( MIT , ERCIM , Keio , Beihang ). 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. Other documents may supersede this document. 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 Applications Working Group as an Editor's Draft.
GitHub Issues are preferred for discussion of this specification.
Publication as an Editor's Draft does not imply endorsement by the W3C Membership. 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 1 March 2019 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.
Editing
hosts
that
are
not
inside
a
document
cannot
have
a
selection
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
,
the
selection
must
be
associated
with
a
new
range
object,
as
required
elsewhere
in
this
specification.
addRange
()
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
empty,
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.
This short-changes Mac users. See bug 13909 .
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
.
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
.
Selection
interface
provides
a
way
to
interact
with
the
selection
associated
with
each
document.
[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
;
Range getRangeAt
(unsigned long index);
void addRange
(Range range);
void removeRange
(Range range);
void removeAllRanges
();
void empty
();
void collapse
(Node? node, optional unsigned long offset = 0);
void setPosition
(Node? node, optional unsigned long offset = 0);
void collapseToStart
();
void collapseToEnd
();
void extend
(Node node, optional unsigned long offset = 0);
void setBaseAndExtent
(Node anchorNode, unsigned long anchorOffset, Node focusNode, unsigned long focusOffset);
void selectAllChildren
(Node node);
[CEReactions]
void deleteFromDocument
();
boolean containsNode
(Node node, optional boolean allowPartialContainment = false);
stringifier DOMString ();
};
anchorNode
The
attribute
must
return
the
anchor
node
of
the
context
object
,
or
null
if
the
anchor
is
null.
anchorOffset
The
attribute
must
return
the
anchor
offset
of
the
context
object
,
or
0
if
the
anchor
is
null.
focusNode
The
attribute
must
return
the
focus
node
of
the
context
object
,
or
null
if
the
anchor
is
null.
focusOffset
The
attribute
must
return
the
focus
offset
of
the
context
object
,
or
0
if
the
focus
is
null.
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
the
context
object
is
empty
,
and
must
return
1
otherwise.
type
The
attribute
must
return
"None"
if
the
context
object
is
empty
,
"Caret"
if
the
context
object
's
range
is
collapsed
,
and
"Range"
otherwise.
getRangeAt()
method
The
method
must
throw
an
IndexSizeError
exception
if
index
is
not
0
,
or
if
the
context
object
is
empty
.
Otherwise,
it
must
return
a
reference
to
(not
a
copy
of)
the
context
object
's
range
.
Thus
subsequent
calls
of
this
method
returns
the
same
range
object
if
nothing
has
removed
the
context
object
's
range
in
the
meantime.
In
particular,
getSelection().getRangeAt(0)
===
getSelection().getRangeAt(0)
evaluates
to
true
if
the
selection
is
not
empty
.
IE9 and Firefox 4.0 return the same object every time, as the spec says. Chrome 12 dev and Opera 11.10 return a different object every time.
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
the
context
object
'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
the
context
object
empty
by
disassociating
its
range
if
the
context
object
's
range
is
range
.
Otherwise,
it
must
throw
a
NotFoundError
.
removeAllRanges()
method
The method must make the context object empty by disassociating its range if the context object has an associated range .
empty
The
method
must
be
an
alias,
and
behave
identically,
to
removeAllRanges()
.
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
context
object
is
empty
.
Otherwise,
it
must
create
a
new
range
,
set
both
its
start
and
end
to
the
start
of
the
context
object
's
range
,
and
then
set
the
context
object
'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
context
object
is
empty
.
Otherwise,
it
must
create
a
new
range
,
set
both
its
start
and
end
to
the
end
of
the
context
object
's
range
,
and
then
set
the
context
object
'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.)
deleteFromDocument()
method
The
method
must
invoke
deleteContents
()
on
the
context
object
's
range
if
the
context
object
is
not
empty
.
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
the
context
object
is
empty
or
if
node
's
root
is
not
the
document
associated
with
the
context
object
.
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
first
boundary
point
in
the
node
or
end
of
its
range
is
after
or
visually
equivalent
to
the
last
boundary
point
in
the
node
.
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
below.
This specification extends several interfaces to provide entry points to the interfaces defined in this specification.
Document
interface
The
Document
interface
is
defined
in
[
HTML
].
partial interface Document
{
Selection? getSelection
();
};
getSelection()
method
The
method
must
return
the
selection
associated
with
context
object
if
the
context
object
has
an
associated
browsing
context
,
and
it
must
return
null
otherwise.
If
we
create
a
Document
object
with
no
browsing
context
(say
via
document.implementation.createHTMLDocument("")
and
call
on
it),
IE9
seems
to
return
a
different
Selection
object.
Firefox
12.0a1
and
Opera
Next
12.00
alpha
return
the
same
object
as
for
the
current
window.
Chrome
17
dev
returns
null.
See
discussion
.
There's
no
meaningful
selection
associated
with
such
a
document,
so
we
follow
WebKit
and
require
returning
getSelection
()
null
.
Window
interface
The
Window
interface
is
defined
in
[
HTML
].
partial interface Window
{
Selection? getSelection
();
};
getSelection()
method
The
method
must
invoke
and
return
the
result
of
on
the
context
object
's
getSelection
()
attribute.
Window
.
document
GlobalEventHandlers
interface
The
GlobalEventHandlers
interface
is
defined
in
[
HTML
].
partial 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
,
objects,
and
Document
objects.
Window
onselectionchange
The
attribute
must
be
an
event
handler
IDL
attribute
for
the
selectionchange
event
supported
by
all
HTML
elements
,
objects,
and
Document
objects.
Window
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.
selectstart
event
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
with
the
name
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
.
selectionchange
event
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
queue
a
task
to
fire
an
event
with
the
name
selectionchange
,
which
does
not
bubble
and
is
not
cancelable,
at
the
document
associated
with
the
selection
.
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.
Many thanks to