Enable :focus only on keyboard use (or tab press)
Update: This issue may no longer be relevant
Some other posters have mentioned the :focus-visible
pseudo class - which now has decent browser support...
I would like to add, that based on the spec which covers the :focus-visible pseudo class, browsers should now only indicate focus when it is helpful to the user - such as in cases where the user interacts with the page via a keyboard or some other non-pointing device
This basically means that the original issue is no longer relevant, because now, when a user clicks/taps a button (or another focusable element), the User Agent won't show the focus ring anymore - even though the button is focused - because in this case the focus ring isn't helpful to the user.
From the spec:
While the :focus pseudo-class always matches the currently-focused
element, UAs only sometimes visibly indicate focus (such as by
drawing a “focus ring”), instead using a variety of heuristics to
visibly indicate the focus only when it would be most helpful to the
user. The :focus-visible pseudo-class matches a focused element in
these situations only...
Indeed, as of version 90, Chromium’s User Agent stylesheet switched from :focus
to :focus-visible, and as a result of this change, button clicks and taps no longer invoke focus rings
Also, as of version 87, Firefox also uses :focus-visible on their User Agent style.
All that being said, if custom focus styles are needed, since focus styles have now shifted from :focus
to :focus-visible
, when overriding the default styles with custom focus styles - the :focus-visible
pseudo class should be used.
Something like this:
button:focus-visible {
/* remove default focus style */
outline: none;
/* custom focus styles */
box-shadow: 0 0 2px 2px #51a7e8;
color: lime;
}
Backwards Compatibility:
The possible problem with using :focus-visible like this, is that browsers which don't support :focus-visible
, will show the default focus ring, which may not be clear or visible - depending on the design.
Šime Vidas, in this article, describes a viable strategy to currently use the :focus-visible pseudo class - which would work even in browsers which don't yet support :focus-visible -
A good way to start using :focus-visible today is to define the focus
styles in a :focus rule and then immediately undo these same styles in
a :focus:not(:focus-visible) rule. This is admittedly not the most
elegant and intuitive pattern, but it works well in all browsers:Browsers that don’t support :focus-visible use the focus styles
defined in the :focus rule and ignore the second style rule completely
(because :focus-visible is unknown to them).In browsers that do support :focus-visible, the second style rule
reverts the focus styles defined in the :focus rule if the
:focus-visible state isn’t active as well. In other words, the focus
styles defined in the :focus rule are only in effect when
:focus-visible is also active.
button:focus {
outline: none;
background: #ffdd00; /* gold */
}
button:focus:not(:focus-visible) {
background: white; /* undo gold */
}
Original Answer:
This excellent article by Roman Komarov poses a viable solution for achieving keyboard-only focus styles for buttons, links and other container elements such as spans or divs (which are artificially made focusable with the tabindex attribute)
The Solution:
button {
-moz-appearance: none;
-webkit-appearance: none;
background: none;
border: none;
outline: none;
font-size: inherit;
}
.btn {
all: initial;
margin: 1em;
display: inline-block;
}
.btn__content {
background: orange;
padding: 1em;
cursor: pointer;
display: inline-block;
}
/* Fixing the Safari bug for `<button>`s overflow */
.btn__content {
position: relative;
}
/* All the states on the inner element */
.btn:hover > .btn__content {
background: salmon;
}
.btn:active > .btn__content {
background: darkorange;
}
.btn:focus > .btn__content {
box-shadow: 0 0 2px 2px #51a7e8;
color: lime;
}
/* Removing default outline only after we've added our custom one */
.btn:focus,
.btn__content:focus {
outline: none;
}
<h2>Keyboard-only focus styles</h2>
<button id="btn" class="btn" type="button">
<span class="btn__content" tabindex="-1">
I'm a button!
</span>
</button>
<a class="btn" href="#x">
<span class="btn__content" tabindex="-1">
I'm a link!
</span>
</a>
<span class="btn" tabindex="0">
<span class="btn__content" tabindex="-1">
I'm a span!
</span>
</span>
<p>Try clicking any of the the 3 focusable elements above - no focus styles will show</p>
<p>Now try tabbing - behold - focus styles</p>
Why pressing TAB key (:focus effect) causes positioned off-the-screen div element with input field inside it to appear on the screen?
Set a tabIndex
of -1
to prevent tab focusability to elements that you don't want to gain focus with the tab key.
Label that wraps an input - how to make focus style visible only when focused using the keyboard, not mouse click?
Update the styles of the input inside it so it can style get the focus while being visually hidden:
label {
position:relative;
}
.visually-hidden {
position: absolute;
inset: 0;
margin: 0;
padding: 0;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
overflow: hidden;
}
button:focus-visible,
input:focus-visible{
outline: 4px solid red;
}
body {
margin: 40px;
}
div {
display: flex;
gap: 20px;
}
<div>
<input type="text" />
<button>Submit</button>
<label>
<input class="visually-hidden" type="checkbox" />
Label
</label>
</div>
tabIndex doesn't make a label focusable using Tab key
Why doesn't tabindex make the label focusable?
Short Answer:
- Label is focusable.
- TabIndex won't make any difference.
- Welcome to the world of browser/agent inconsistencies.
tl;dr;
The label
(Ref) element is very much focusable. Its DOM Interface is HTMLLabelElement
which derives from HTMLElement
(Ref) which in turn implements GlobalEventHandlers
(Ref) and hence exposes the focus()
method and onfocus
event handler.
The reason you are unable to get hold of proper specification / reference document for label
s focus behaviour, is because you might have been looking at HTML5 Specs. Interestingly, HTML5 refs do not state anything relating to that, which adds to the confusion.
This is mentioned in the HTML 4.01 Ref here: http://www.w3.org/TR/html401/interact/forms.html#h-17.9.1
Specifically near the end of section 17.9.1 and just before 17.10:
When a LABEL element receives focus, it passes the focus on to its
associated control.
Also, elsewhere (I am unable to get hold of that part of the ref) I have read that it depends on the implementing agent. (Don't take my word for that, am not too sure).
However, what it means is that when you focus
a label
(or a label
received a focus
), that focus
is passed on to its associated labeleable control. This will not result in two different focus
es, but one focus
on the input
(in your case a checkbox). Because of this behaviour, tabindex
property cannot play a role.
There is also a test suite by W3C for website accessibility (WAAG) here: http://www.w3.org/WAI/UA/TS/html401/cp0102/0102-ONFOCUS-ONBLUR-LABEL.html which, discusses the implementation of onfocus
and onblur
for a label
. Ideally a keyboard or an assistive technology that emulates the keyboard should implement this. But...
This is where the browser inconsistencies play their role.
This can be demonstrated by this example. Check the following snippet in different browsers. (I have tested it against IE-11, GC-39 and FF-34. All of them behave differently.)
- Click the button "Focus Label"
- It should focus the label, then pass the focus and highlight its associated checkbox outline in blue.
- Chrome-v39 works. IE-v11 it doesn't (somehow html and body do respond to :focus). FF-v34 it works.
Talking about browser inconsistencies, try using the "access key" L. Some browsers will focus the checkbox whereas some will click it i.e. pass the action to it.
Here is a fiddle to test it: http://jsfiddle.net/abhitalks/ff0xds4z/2/
Here is a snippet:
label = $("label").first();$("#btn").on("click", function() { label.focus();});
* { margin: 8px; }.highlight { background-color: yellow; }:focus { outline: 2px solid blue;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><input id="txt" type="text" value="input" /><br /><label for="chk" accesskey="L">Checkbox: </label><input id="chk" type="checkbox" /><br /><input id="btn" type="button" value="Focus Label" />
Add Focus To Pop Up / Modal On Click For Tabbing / Accessibility - JavaScript
You have to add focus to the pop-up right after this appears, when you do it simultaneously with closeButton.focus()
only it won't work that's why I'm using setTimeout(() => closeButton.focus(), 1)
, this will added it focus after a 1
millisecond.
At first, focus on a button isn't visible, it become visible when arrow keys are pressed, so I make it visible styling it:
.close:focus {
border: 2px solid black;
border-radius: 5px;
}
The whole code:
let clickMe = document.querySelector("#click-me"),
modal = document.querySelector(".modal"),
closeButton = document.querySelector(".close");
clickMe.addEventListener("click", () => {
setTimeout(() => closeButton.focus(), 1);
modal.style.display = "flex";
});
closeButton.addEventListener("click", () => {
modal.style.display = "none";
});
body {
margin: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
input,
button {
margin: 1rem;
padding: 0.5rem;
}
.click-me {
display: block;
}
.modal {
display: none;
flex-direction: column;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
background: gray;
position: absolute;
}
form {
display: flex;
}
.close:focus {
border: 2px solid black;
border-radius: 5px;
}
<button id="click-me">Click Me</button>
<form action="">
<input type="text" placeholder="An Input" />
<input type="text" placeholder="An Input" />
<input type="text" placeholder="An Input" />
<input type="text" placeholder="An Input" />
</form>
<div class="modal">
<button class="close">Close x</button>
<button>More Buttons</button>
<button>More Buttons</button>
</div>
Input Verifier effect not work by click, just work by tab button
The purpose of InputVerifier
class is to help clients support smooth focus navigation through GUIs with text fields. Before focus is transfered to another Swing component that requests it, the input verifier's shouldYieldFocus
method is called(which ask the verify
function to validate data). Focus is transfered only if that method returns true
.
Please Try to fix the issues about using InutVerifier
, verify
and shouldYieldFunction
as mentioned in your previous post. If you are not going to change your practice, you will be danger in future. Remove you components enabling and disabling code from verify function.
Your Problem in this post: In this case, what really happening is that, when your data is invalid and you try to lose your input text field focus by clicking another component, your JRadioButtons
get disabled. A disabled cant be focused until it is re-enabled. As input-verifier responds with focus-lose event, clicking on the disabled RadioButton
isn't resulting in focus navigation, and thus ShouldYieldFocus(which calls verify)
is not being called to re-enable your components.
Pressing the tab works, because it is sending the Focus to your second text input field according to swing's focus traversal policy. Hence a focus lose event occur on first input text field and this time InputVerifier
's verify function get called which eventually enables your component. To understand the problem better, try rewriting your own example with one JRadioButton
and one JTextFeild
.
Try using a DocumentListener
with your text Field. upon data insertion and removal event, check your data validity using InputVerifier
and then, enable/disable related components.
I am writing a sample code snippets to demonstrate, how adding DocumentListener
to your fNameTF
and lNameTF
text fields will resolve your problem:
fNameTF.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
doOnDataValidity(verifier.verify(fNameTF));
}
@Override
public void removeUpdate(DocumentEvent e) {
doOnDataValidity(verifier.verify(fNameTF));
}
@Override
public void changedUpdate(DocumentEvent e) {}
});
doOnValidity(boolean isValid)
function is as follows:
public void doOnDataValidity(boolean isDataValid)
{
if(isDataValid)
{
//enable your components
}else
{
//disable your components
}
}
Add a DocumentListener to your lNameTf.getDocument()
the same way.
Tutorial Resources: How to use DocumentListener.
Related Topics
Which CSS Selector Is Stronger
Css3 Transform Causing Text to Flicker in Safari and Firefox MAC Yosemite
Aptana Studio 3 Code Assist for SASS (.Scss) Files
Style the First <Td> Column of a Table Differently
How to Maintain Png Alpha Transparency When Using "-Ms-Filter" Property
CSS Grid: How to Apply Color to Grid Gaps
How to Exclude a Specific Element from Inheriting CSS Rules
Position:Sticky Is Not Working
Using Nth-Child in Tables Tr Td
Two HTML Tables Side by Side, Centered on the Page
How to Use CSS to Vertically Center the Text in an Anchor, Within a Li
Css3 Scale Transform on Parent Div But Keeping Constant Size in Some of the Associated Divs
CSS Relative + Right (Or Bottom) Almost Never Work
Why Do I Get the Error Message "Element 'Style' Cannot Be Nested Within Element 'Style'"
Margin-Bottom for <A> Link Elements