Pyae Phyoe Shein
Pyae Phyoe Shein

Reputation: 13787

How to change parent style when child receives focus in CSS

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>

Upvotes: 2

Views: 2995

Answers (5)

Enes &#214;nder
Enes &#214;nder

Reputation: 21

A long time has passed since this question, but I see that there is still no answer. You can do whatever you want like this:

#email:has(input:focus) {
   /* some style */
}

Upvotes: 2

Justin Dalrymple
Justin Dalrymple

Reputation: 868

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;
}

Upvotes: 2

paulflakstad
paulflakstad

Reputation: 88

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>

Upvotes: 2

Rajshekar Reddy
Rajshekar Reddy

Reputation: 18987

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');
 });

Upvotes: 0

Kamil Powroźnik
Kamil Powroźnik

Reputation: 75

Use jQuery.

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

Upvotes: 0

Related Questions