Using :focus to style outer div?

CssFocusStylesheet

Css Problem Overview


When I begin writing text in the textarea, I want the outer div, with a class box, to have its border turned solid instead of dashed, but somehow the :focus doesn't apply in this case. If it works with :active, how come it doesn't work with :focus?

Any ideas why?

(Note. I want the DIV's border to turn solid, NOT the textareas)

div.box
{
    width: 300px;
    height: 300px;
    border: thin dashed black;
}

div.box:focus{
    border: thin solid black;
}

<div class="box">
    <textarea rows="10" cols="25"></textarea>
</div>

Css Solutions


Solution 1 - Css

Other posters have already explained why the :focus pseudo class is insufficient, but finally there is a CSS-based standard solution.

CSS Selectors Level 4 defines a new pseudo class:

:focus-within

From MDN:

> The :focus-within CSS pseudo-class matches any element that the :focus > pseudo-class matches or that has a descendant that the :focus > pseudo-class matches. (This includes descendants in shadow trees.)

So now with the :focus-within pseudo class - styling the outer div when the textarea gets clicked becomes trivial.

.box:focus-within {
    border: thin solid black;
}

.box {
    width: 300px;
    height: 300px;
    border: 5px dashed red;
}

.box:focus-within {
    border: 5px solid green;
}

<p>The outer box border changes when the textarea gets focus.</p>
<div class="box">
    <textarea rows="10" cols="25"></textarea>
</div>

Codepen demo

NB: Browser Support : Chrome (60+), Firefox and Safari

Solution 2 - Css

DIV elements can get focus if set the tabindex attribute. Here is the working example.

#focus-example > .extra {
  display: none;
}
#focus-example:focus > .extra {
  display: block;
}

<div id="focus-example" tabindex="0">
  <div>Focus me!</div>
  <div class="extra">Hooray!</div>
</div>

For more information about focus and blur, you can check out this article.

Update: And here is another example using focus to create a menu.

#toggleMenu:focus {
  outline: none;
}
button:focus + .menu {
  display: block;
}
.menu {
  display: none;
}
.menu:focus {
  display: none;
}

<div id="toggleMenu" tabindex="0">
  <button type="button">Menu</button>
  <ul class="menu" tabindex="1">
    <li>Home</li>
    <li>About Me</li>
    <li>Contacts</li>
  </ul>
</div>

Solution 3 - Css

While this can't be achieved with CSS/HTML alone, it can be achieved with JavaScript (without need of a library):

var textareas = document.getElementsByTagName('textarea');

for (i=0;i<textareas.length;i++){
    // you can omit the 'if' if you want to style the parent node regardless of its
    // element type
    if (textareas[i].parentNode.tagName.toString().toLowerCase() == 'div') {
        textareas[i].onfocus = function(){
            this.parentNode.style.borderStyle = 'solid';
        }
        textareas[i].onblur = function(){
            this.parentNode.style.borderStyle = 'dashed';
        }
    }
}

JS Fiddle demo.

Incidentally, with a library, such as jQuery, the above could be condensed down to:

$('textarea').focus(
    function(){
        $(this).parent('div').css('border-style','solid');
    }).blur(
    function(){
        $(this).parent('div').css('border-style','dashed');
    });

JS Fiddle demo.

References:

Solution 4 - Css

This can now be achieve through the css method :focus-within as examplified in this post: http://www.scottohara.me/blog/2017/05/14/focus-within.html

/*
  A normal (though ugly) focus
  pseudo-class.  Any element that
  can receive focus within the
  .my-element parent will receive
  a yellow background.
*/
.my-element *:focus {
  background: yellow !important;
  color: #000;
}

/*
  The :focus-within pseudo-class
  will NOT style the elements within
  the .my-element selector, like the
  normal :focus above, but will
  style the .my-element container
  when its focusable children
  receive focus.
*/
.my-element:focus-within {
  outline: 3px solid #333;
}

<div class="my-element">
  <p>A paragraph</p>
  <p>
    <a href="http://scottohara.me">
      My Website
    </a>
  </p>

  <label for="wut_email">
    Your email:
  </label>
  <input type="email" id="wut_email" />
</div>

Solution 5 - Css

As per the spec:

> The :focus pseudo-class applies while an element has the focus (accepts keyboard events or other forms of text input).

The <div> does not accept input, so it cannot have :focus. Furthermore, CSS does not allow you to set styles on an element based on targeting its descendants. So you can't really do this unless you are willing to use JavaScript.

Solution 6 - Css

Simple use JQuery.

$(document).ready(function() {
  $("div .FormRow").focusin(function() {
    $(this).css("background-color", "#FFFFCC");
    $(this).css("border", "3px solid #555");
  });
  $("div .FormRow").focusout(function() {
    $(this).css("background-color", "#FFFFFF");
    $(this).css("border", "0px solid #555");
  });
});

    .FormRow {
      padding: 10px;
    }

<html>

<head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
</head>

<body>
  <div style="border: 0px solid black;padding:10px;">
    <div class="FormRow">
      First Name:
      <input type="text">
      <br>
    </div>
    <div class="FormRow">
      Last Name:
      <input type="text">
    </div>
  </div>

  <ul>
    <li><strong><em>Click an input field to get focus.</em></strong>
    </li>
    <li><strong><em>Click outside an input field to lose focus.</em></strong>
    </li>
  </ul>
</body>

</html>

Solution 7 - Css

focus-within

.box:focus-within {
  background: cyan;
}

read more here

Solution 8 - Css

You can tab between div tags. Just add a tab index to the div. It's best to use jQuery and CSS classes to solve this problem. Here's a working sample tested in IE, Firefox, and Chrome (Latest versions... didn't test older).

<html>
	<head>
		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
		<script type="text/javascript">
			var divParentIdFocus;
			var divParentIdUnfocus = null;
			
			$(document).ready(function() {				
			
					$("div").focus(function() {
						//$(this).attr("class", "highlight");
						var curDivId = $(this).attr("id");
						
						// This Check needs to be performed when/if div regains focus
						// from child element.
						if (divParentIdFocus != curDivId){
							divParentIdUnfocus = divParentIdFocus;
							divParentIdFocus = curDivId;
							refreshHighlight();
						}
						
						divParentIdFocus = curDivId;
					});
					
					
					$("textarea").focus(function(){
						var curDivId = $(this).closest("div").attr("id");
						
						if(divParentIdFocus != curDivId){
							divParentIdUnfocus = divParentIdFocus;
							divParentIdFocus = curDivId;
							refreshHighlight();
						}
					});
					
					$("#div1").focus();
			});
			
			function refreshHighlight()
			{
				if(divParentIdUnfocus != null){
					$("#" +divParentIdUnfocus).attr("class", "noHighlight");
					divParentIdUnfocus = null;
				}
				
				$("#" + divParentIdFocus).attr("class", "highlight");
			}
		</script>
		<style type="text/css">
			.highlight{
				background-color:blue;
				border: 3px solid black;
				font-weight:bold;
				color: white;
			}
			.noHighlight{			
			}
            div, h1,textarea, select { outline: none; }
			
		</style>
	<head>
	<body>
		<div id = "div1" tabindex="100">
			<h1>Div 1</h1> <br />
			<textarea rows="2" cols="25" tabindex="101">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="102">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="103">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="104">~Your Text Here~</textarea> <br />
		</div>
		<div id = "div2" tabindex="200">
			<h1>Div 2</h1> <br />
			<textarea rows="2" cols="25" tabindex="201">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="202">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="203">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="204">~Your Text Here~</textarea> <br />
		</div>
		<div id = "div3" tabindex="300">
			<h1>Div 3</h1> <br />
			<textarea rows="2" cols="25" tabindex="301">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="302">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="303">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="304">~Your Text Here~</textarea> <br />
		</div>
		<div id = "div4" tabindex="400">
			<h1>Div 4</h1> <br />
			<textarea rows="2" cols="25" tabindex="401">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="402">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="403">~Your Text Here~</textarea> <br />
			<textarea rows="2" cols="25" tabindex="404">~Your Text Here~</textarea> <br />
		</div>		
	</body>
</html>

Solution 9 - Css

As far as I am aware you have to use javascript to travel up the dom.

Something like this:

$("textarea:focus").parent().attr("border", "thin solid black");

you'll need the jQuery libraries loaded as well.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWeblurkView Question on Stackoverflow
Solution 1 - CssDanieldView Answer on Stackoverflow
Solution 2 - CssKarlen KishmiryanView Answer on Stackoverflow
Solution 3 - CssDavid ThomasView Answer on Stackoverflow
Solution 4 - CssTekillView Answer on Stackoverflow
Solution 5 - CssJonView Answer on Stackoverflow
Solution 6 - CssMatthew EganView Answer on Stackoverflow
Solution 7 - CssMoliereView Answer on Stackoverflow
Solution 8 - CssThomas VanderhoofView Answer on Stackoverflow
Solution 9 - CssCBRRacerView Answer on Stackoverflow