Search code examples
javascripthtmlcssangularjsfocus

CSS: Change parent on focus of child


Let's say you have something like:

<div class="parent">
    <input class="childInput" type="text" />
    <div class="sibling"></div>
</div>

I want to change the appearance of the parent/siblings when the child receives focus. Are there any CSS tricks for doing stuff like this?


The reason for my question is as follows:

I'm creating an Angular app which needs editable text fields. It should look like a label until it is clicked, at which point it should look like a normal text input. I styled the text field based on :focus to achieve this effect, but the text is cut off by text input's boundaries.

I also used ng-show, ng-hide, ng-blur, ng-keypress and ng-click to switch between the label and the text input based on blurs, key presses and clicks.

This worked fine except for one thing: After the label's ng-click="setEdit(this, $event)" changes the edit boolean used by ng-show and ng-hide to true, it uses a jQuery call to .select() the text input. However, it isn't until after the completion of the ng-click that everything is $digest'd, so the text input loses focus again.

Since the text input never actually receives focus, using ng-blur to revert back to showing the label is buggy: The user has to click in the text input and then click out of it again to revert back to showing the label.

Edit:

Here's an example plunk of the issue: http://plnkr.co/edit/synSIP?p=preview


Solution

  • You can now do this in pure CSS, so no JavaScript needed 😁

    The new CSS pseudo-class :focus-within would help for cases like this and will help with accessibility when people use tabbing for navigating, common when using screen readers.

    .parent:focus-within {
      border: 1px solid #000;
    }
    

    The :focus-within pseudo-class matches elements that either themselves match :focus or that have descendants which match :focus.


    Can I use...

    You can check which browsers support this by visiting http://caniuse.com/#search=focus-within


    Demo

    fieldset {
      padding: 0 24px 24px !important;
    }
    
    fieldset legend {
      opacity: 0;
      padding: 0 8px;
      width: auto;
    }
    
    fieldset:focus-within {
      border: 1px solid #000;
    }
    
    fieldset:focus-within legend {
      opacity: 1;
    }
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />
    
    <div class="container">
      <form>
        <fieldset>
          <legend>Parent Element</legend>
          <div class="form-group">
            <label for="name">Name:</label>
            <input class="form-control" id="name" placeholder="Enter name">
          </div>
          <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" class="form-control" id="email" placeholder="Enter email">
          </div>
        </fieldset>
      </form>
    </div>