0

I want to change parent <div> style when a child <input> element receives focus. Unfortunately, the following code does not work at all. Please help me how to do it?

#email {
    opacity: 0.3;
}

#exampleInputEmail1:focus < #email {
    background: #f90442;
}

<div class="form-group form-group-lg" id="email" tabindex="0">
    <label>Email address</label>
    <input type="email" class="form-control" id="exampleInputEmail1" placeholder="Email">
</div>
PPShein
  • 10,951
  • 34
  • 129
  • 188

4 Answers4

1

Unfortunately, there are no parent selectors in CSS, not even in CSS3.

You will have to use a workaround – namely javascript of some kind.

How to approach this with javascript has to be decided in each case. Arguably, the easiest and most "accessible" solution is probably to use jQuery, and there are quite a few options.

For example, you could target the parent wrapper with the :has() selector:

$(".form-group").has(":focus")

This will target any element with class="form-group [...]" that has an element with focus among its descendants (not just as an immediate child).

Or you can use the .closest() function:

$(":focus").closest(".form-group") 

Unlike the similar .parents() function, .closest() stops traversing up the DOM tree once the selector is matched. This likely makes .closest() the more efficient option of the two here.

The two examples above are both lenient with respect to the DOM structure, and less likely to break if it changes. However, if the wrapper element will always be an immediate parent of the <input>, you can use the .parent() function (with an optional selector):

// Option 1: Targets the immediate parent
$("input:focus").parent()
// Option 2: Targets the immediate parent, but only if it's a div
$("input:focus").parent("div")

Example implementation of these 4 options, works by toggling an .infocus class on the wrapper (also available as jsfiddle):

// Adds or removes a focus class.
function updateFocus(e) {
 // Log the event to view details about it
  // console.log(e);
  
  // The "has focus" class name
  var focusClass = "infocus";
  // The wrapper element selector
  var wrapperSel = ".form-group";
  
  
  //*===========================================================
  // Option 1: has(":focus")
  // - needs only the wrapper selector
  // ===========================================================
  var wrapper = $(wrapperSel);
  // Remove the class on all
  //wrapper.each(function() { $(this).removeClass(focusClass);});
  wrapper.removeClass(focusClass);
  // Add class only to the one whose descendant has focus
  wrapper.has(":focus").addClass(focusClass);
  //*/
  
  /* ===========================================================
  // Option 2: closest()
  // - needs the event and the wrapper selector
  // ===========================================================
  if (e.type === "focus") {
   $(e.target).closest(wrapperSel).addClass(focusClass);
  } else if (e.type === "blur") {
    $(e.target).closest(wrapperSel).removeClass(focusClass);
  }
  //*/
  
  /* ===========================================================
  // Option 3: parents()
  // - needs the event and the wrapper selector
  // ===========================================================
  if (e.type === "focus") {
   $(e.target).parents(wrapperSel).addClass(focusClass);
  } else if (e.type === "blur") {
    $(e.target).parents(wrapperSel).removeClass(focusClass);
  }
  //*/
  
  /* ===========================================================
  // Option 4: parent()
  // - needs only the event (the wrapper selector is optional)
  // ===========================================================
  if (e.type === "focus") {
   $(e.target).parent().addClass(focusClass);
  } else if (e.type === "blur") {
    $(e.target).parent().removeClass(focusClass);
  }
  //*/
}

// Bind the updateFocus() function above to focus/blur of form elements.
$('input, textarea, select').on("focus", function(event) {
 updateFocus(event);
}).on("blur", function(event) {
 updateFocus(event);
});
.form-group {
    opacity: 0.3;
}
.form-group.infocus {
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="form-group">
  <label>Email</label>
  <input type="email" placeholder="Email">
</div>

<div class="form-group">
  <label>Name</label>
  <input type="text" placeholder="Name">
</div>
Community
  • 1
  • 1
  • Link-only answers are invalid in stackoverflow. It's called poor quality answer. Please, read how to answer: http://stackoverflow.com/help/how-to-answer – Marcos Pérez Gude Oct 27 '16 at 11:24
  • Thanks for the help link, Marcos, and sorry if I did something bad. I'm new to writing answers, and will keep this in mind in the future. Not sure I agree with you that this is an "invalid answer" though, or that it is a "link-only answer". Admittedly, it is a _partial_ answer, no doubt, but it has meaning in itself; Even without the links, it spells out the problem and hints to a solution—which is covered more thoroughly on the linked page. – paulflakstad Oct 27 '16 at 11:53
  • Please click the edit button under the answer and add the relevant content to the answer. – Mike Oct 27 '16 at 12:15
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/14114918) – Paul T. Rawkeen Oct 27 '16 at 13:00
  • As @PaulT.Rawkeen said, you need to put the link's content into the answer. When the links change, this answer will be invalid and obsolete. Provide de details into the answer, and will be ok. :) – Marcos Pérez Gude Oct 27 '16 at 13:36
  • Updated my answer. Hope it's OK now, and I'd like to point out that "any answer that gets the asker going in the right direction is helpful", and this is why I thought my original answer was OK. I never intended to provide a complete solution, just a partial answer (which is also allowed). My only intent was to make the OP aware of an important fact that (s)he seemed to have missed. Anyway, thanks for your input and correction. I appreciate it, and will keep what you have said in mind. – paulflakstad Oct 27 '16 at 14:17
0

Use jQuery.

$("#exampleInputEmail1").focus(function() {
    //change style
});
0

What you are asking for is not possible in CSS as of now. So only option is to use Jquery.

If interested read on..

Use jquery to bind a on focus event on the input element, And in this event you just need to access the parent and change its background-color.

Have a CSS like below.

.background-color-RED{
  background-color:#f90442;
}

Jquery syntax like below.

$("#exampleInputEmail1").on('focus',function() {
   $(this).parent().addClass('background-color-RED');
});

Extra: If you want to remove the background color when the user focus out of the input then you can use blur event and handle it as below.

 $("#exampleInputEmail1").on('blur',function() {
    $(this).parent().removeClass('background-color-RED');
 });
Rajshekar Reddy
  • 17,202
  • 3
  • 34
  • 54
0

Quick update on this one, this can be sort of accomplished using focus-within:

/* Selects a <div> when one of its descendants is focused */
div:focus-within {
  background: cyan;
}
Justin Dalrymple
  • 185
  • 1
  • 10