要素は、ユーザーがクリックするか、キーボードのTabキーを使用するとフォーカスを受け取ります。また、ページが読み込まれたときにデフォルトで要素にフォーカスを当てる autofocus
HTML属性や、フォーカスを取得する他の手段もあります。
一般的に、要素にフォーカスが当たるということは、「ここにデータを受け入れる準備をする」という意味で、必要な機能を初期化するためのコードを実行できる瞬間です。
フォーカスを失う(「ブラー」)瞬間はさらに重要となる場合があります。ユーザーが別の場所をクリックしたり、Tabを押して次のフォームフィールドに移動したり、他の手段がある場合です。
一般的に、フォーカスを失うということは、「データが入力された」という意味なので、それをチェックしたり、サーバーに保存したりするなどのコードを実行できます。
フォーカスイベントを扱う際には重要な特性があります。それらについては後で詳しく説明します。
イベント focus/blur
フォーカス時にfocus
イベントが呼び出され、要素がフォーカスを失うとblur
イベントが呼び出されます。
入力フィールドの検証に使用してみましょう。
以下の例では、
blur
ハンドラーは、フィールドにメールアドレスが入力されているかどうかをチェックし、入力されていない場合はエラーを表示します。focus
ハンドラーはエラーメッセージを非表示にします(blur
時に再度チェックされます)。
<
style
>
.invalid
{
border-color
:
red
;
}
#error
{
color
:
red
}
</
style
>
Your email please: <
input
type
=
"
email"
id
=
"
input"
>
<
div
id
=
"
error"
>
</
div
>
<
script
>
input.
onblur
=
function
(
)
{
if
(
!
input.
value.
includes
(
'@'
)
)
{
// not email
input.
classList.
add
(
'invalid'
)
;
error.
innerHTML =
'Please enter a correct email.'
}
}
;
input.
onfocus
=
function
(
)
{
if
(
this
.
classList.
contains
(
'invalid'
)
)
{
// remove the "error" indication, because the user wants to re-enter something
this
.
classList.
remove
(
'invalid'
)
;
error.
innerHTML =
""
;
}
}
;
</
script
>
最新のHTMLでは、required
、pattern
などの入力属性を使用して多くの検証を実行できます。そして、必要なものが得られることもあります。JavaScriptは、より柔軟性が必要な場合に使用できます。また、変更された値が正しい場合は、自動的にサーバーに送信することもできます。
メソッド focus/blur
メソッドelem.focus()
とelem.blur()
は、要素のフォーカスを設定/解除します。
たとえば、値が無効な場合、訪問者が入力を離れることができないようにしてみましょう。
<
style
>
.error
{
background
:
red
;
}
</
style
>
Your email please: <
input
type
=
"
email"
id
=
"
input"
>
<
input
type
=
"
text"
style
=
"
width
:
220
px
"
placeholder
=
"
make email invalid and try to focus here"
>
<
script
>
input.
onblur
=
function
(
)
{
if
(
!
this
.
value.
includes
(
'@'
)
)
{
// not email
// show the error
this
.
classList.
add
(
"error"
)
;
// ...and put the focus back
input.
focus
(
)
;
}
else
{
this
.
classList.
remove
(
"error"
)
;
}
}
;
</
script
>
これはFirefox以外のすべてのブラウザで動作します(バグ)。
入力に何かを入力し、Tabキーを使用するか、<input>
から離れてクリックしようとすると、onblur
がフォーカスを戻します。
onblur
内でevent.preventDefault()
を呼び出すことによって「フォーカスが失われるのを防ぐ」ことはできません。これは、onblur
が要素がフォーカスを失った後に動作するためです。
ただし、実際には、このようなものを実装する前に、よく考える必要があります。一般的にはユーザーにエラーを表示する必要はありますが、フォームの入力を進めることを妨げるべきではありません。最初に他のフィールドを入力したい場合があります。
フォーカスを失う原因は多数あります。
その1つは、訪問者が別の場所をクリックしたときです。ただし、JavaScript自体が原因となる可能性もあります。例えば、
alert
はフォーカスを自分自身に移動させるため、要素でフォーカスが失われ(blur
イベント)、alert
が閉じられると、フォーカスが戻ります(focus
イベント)。- 要素がDOMから削除されると、フォーカスも失われます。後で再挿入された場合、フォーカスは戻りません。
これらの機能により、focus/blur
ハンドラーが誤動作し、必要ないときにトリガーされることがあります。
最適な方法は、これらのイベントを使用するときに注意することです。ユーザーによって開始されたフォーカスの喪失を追跡したい場合は、自分でフォーカス喪失を引き起こさないようにする必要があります。
任意の要素でフォーカスを許可する: tabindex
デフォルトでは、多くの要素はフォーカスをサポートしていません。
リストはブラウザ間で多少異なりますが、1つ常に正しいことがあります。focus/blur
のサポートは、訪問者が操作できる要素(<button>
、<input>
、<select>
、<a>
など)で保証されています。
一方、<div>
、<span>
、<table>
など、何かをフォーマットするために存在する要素は、デフォルトではフォーカスできません。メソッドelem.focus()
はそれらでは機能せず、focus/blur
イベントはトリガーされません。
これは、HTML属性tabindex
を使用して変更できます。
tabindex
を持つ要素は、フォーカス可能になります。属性の値は、Tab(または同様のもの)を使用して要素間を切り替えるときの要素の順序番号です。
つまり、2つの要素があり、最初の要素にtabindex="1"
、2番目の要素にtabindex="2"
がある場合、最初の要素でTabを押すと、フォーカスが2番目の要素に移動します。
切り替え順序は次のとおりです。tabindex
が1
以上の要素が最初に表示され(tabindex
順)、次にtabindex
がない要素(例: 通常の<input>
)が表示されます。
一致するtabindex
がない要素は、ドキュメントソースの順序(デフォルトの順序)で切り替えられます。
2つの特別な値があります。
-
tabindex="0"
は、tabindex
がない要素の中に要素を配置します。つまり、要素を切り替えるとき、tabindex=0
の要素はtabindex ≥ 1
の要素の後に移動します。通常、これは要素をフォーカス可能にし、デフォルトの切り替え順序を維持するために使用されます。
<input>
と同等のフォームの一部になるように要素を作成します。 -
tabindex="-1"
は、要素に対するプログラムによるフォーカスのみを許可します。Tabキーはこのような要素を無視しますが、メソッドelem.focus()
は機能します。
たとえば、ここにリストがあります。最初の項目をクリックして、Tabキーを押します。
Click the first item and press Tab. Keep track of the order. Please note that many subsequent Tabs can move the focus out of the iframe in the example.
<
ul
>
<
li
tabindex
=
"
1"
>
One</
li
>
<
li
tabindex
=
"
0"
>
Zero</
li
>
<
li
tabindex
=
"
2"
>
Two</
li
>
<
li
tabindex
=
"
-1"
>
Minus one</
li
>
</
ul
>
<
style
>
li
{
cursor
:
pointer;
}
:focus
{
outline
:
1
px
dashed green
;
}
</
style
>
順序は次のようになります: 1 - 2 - 0
。通常、<li>
はフォーカスをサポートしませんが、tabindex
は、イベントや:focus
を使用したスタイル設定とともに、完全に有効にします。
elem.tabIndex
も同様に機能します。elem.tabIndex
プロパティを使用して、JavaScriptからtabindex
を追加できます。これは同じ効果があります。
委譲: focusin/focusout
イベントfocus
とblur
はバブリングしません。
たとえば、<form>
にonfocus
を配置して、次のように強調表示することはできません。
<!-- on focusing in the form -- add the class -->
<
form
onfocus
=
"
this
.
className=
'focused'
"
>
<
input
type
=
"
text"
name
=
"
name"
value
=
"
Name"
>
<
input
type
=
"
text"
name
=
"
surname"
value
=
"
Surname"
>
</
form
>
<
style
>
.focused
{
outline
:
1
px
solid red
;
}
</
style
>
上記の例は機能しません。これは、ユーザーが<input>
にフォーカスすると、focus
イベントはその入力でのみトリガーされるためです。これはバブリングされません。したがって、form.onfocus
はトリガーされません。
2つの解決策があります。
1つ目は、おかしな歴史的な機能です。focus/blur
はバブリングしませんが、キャプチャフェーズで下方向に伝播します。
これは機能します。
<
form
id
=
"
form"
>
<
input
type
=
"
text"
name
=
"
name"
value
=
"
Name"
>
<
input
type
=
"
text"
name
=
"
surname"
value
=
"
Surname"
>
</
form
>
<
style
>
.focused
{
outline
:
1
px
solid red
;
}
</
style
>
<
script
>
// put the handler on capturing phase (last argument true)
form.
addEventListener
(
"focus"
,
(
)
=>
form.
classList.
add
(
'focused'
)
,
true
)
;
form.
addEventListener
(
"blur"
,
(
)
=>
form.
classList.
remove
(
'focused'
)
,
true
)
;
</
script
>
2つ目は、focusin
およびfocusout
イベントです。これらは、focus/blur
とまったく同じですが、バブリングします。
これらはon<event>
ではなく、elem.addEventListener
を使用して割り当てる必要があることに注意してください。
したがって、これは別の動作するバリアントです。
<
form
id
=
"
form"
>
<
input
type
=
"
text"
name
=
"
name"
value
=
"
Name"
>
<
input
type
=
"
text"
name
=
"
surname"
value
=
"
Surname"
>
</
form
>
<
style
>
.focused
{
outline
:
1
px
solid red
;
}
</
style
>
<
script
>
form.
addEventListener
(
"focusin"
,
(
)
=>
form.
classList.
add
(
'focused'
)
)
;
form.
addEventListener
(
"focusout"
,
(
)
=>
form.
classList.
remove
(
'focused'
)
)
;
</
script
>
まとめ
イベントfocus
とblur
は、要素のフォーカスがオン/オフになるとトリガーされます。
それらの特別な点は、
- バブリングしません。代わりにキャプチャ状態または
focusin/focusout
を使用できます。 - ほとんどの要素は、デフォルトではフォーカスをサポートしていません。
tabindex
を使用して、あらゆるものをフォーカス可能にします。
現在フォーカスされている要素は、document.activeElement
として使用できます。