165

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?

Edit:

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

AaronF
  • 2,841
  • 3
  • 22
  • 32
  • javascript is no option? – Andi Jun 18 '14 at 13:45
  • 1
    This can't be done using only CSS, you need to use js. – Tushar Jun 18 '14 at 13:47
  • It is, but I was curious if it can be done with styling. I'll add an edit to get into the reason for my question. – AaronF Jun 18 '14 at 13:48
  • 1
    Parent matching can't be done using CSS only. Siblings matching can be done only if the element is adjacent to the defining element. See https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_selectors – haim770 Jun 18 '14 at 13:48
  • see this http://stackoverflow.com/questions/14402514/change-the-div-color-on-input-focus it is the same problem – MickyScion Jun 18 '14 at 13:50

5 Answers5

451

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>
J J B
  • 8,540
  • 1
  • 28
  • 42
4

There is no chance how to do that with CSS. CSS can style only siblings, children, etc. not parents.

You can use simply JS like this:

<style>
.parent {background: green}
.focused {background: red;}
</style>
<div class="parent">
    <input class="childInput" type="text" />
    <div class="sibling"></div>
</div>

<script>
$('.parent > *')
    .focus(function() {
        $('.parent').addClass('focused');
    })
    .blur(function() {
        $('.parent').removeClass('focused');
    });
</script>

http://jsfiddle.net/C4bZ6/

This code takes all direct children of .parent and if you focus one of them, class focused is added to parent. On blur, this class is removed.

pavel
  • 26,538
  • 10
  • 45
  • 61
1

You can use pure CSS to make the text input look like it's not a text input unless it is in focus

http://jsfiddle.net/michaelburtonray/C4bZ6/13/

input[type="text"] {
    border-color: transparent;
    transition-duration: 600ms;
    cursor: pointer;
    outline-style: none;
    text-overflow: ellipsis;
}

input[type="text"]:focus {
    border-color: initial;
    cursor: auto;
    transition-duration: 300ms;
}
Michael
  • 6,895
  • 3
  • 23
  • 19
  • Thanks. I actually tried that, but ran into some issues: "...I styled the text field based on :focus to achieve this effect, but the text is cut off by text input's boundaries...". Showing an ellipsis is definitely better than clipping, but I'd like to see the whole thing, if possible. A related question I just asked is here: http://stackoverflow.com/questions/24289266/select-input-shown-with-ng-show?noredirect=1#comment37532406_24289266, if you're interested. – AaronF Jun 18 '14 at 15:31
1

Try the contenteditible attribute. This may require more work to turn it into usable form data however.

http://jsfiddle.net/michaelburtonray/C4bZ6/20/

<span class="parent" contenteditable>Click me</span>
Michael
  • 6,895
  • 3
  • 23
  • 19
  • 1
    Useful, to be sure. Unfortunately, our client base requires the use of non-HTML5-compliant browsers. – AaronF Jun 18 '14 at 15:53
0

You can style it even for focus-within and not(focus-within) like this (without using JavaScript => more accessible and faster):

        .myform:not(:focus-within) button[type="submit"] {
            display: none;
        }

        .myform:focus-within button[type="submit"] {
            display: block;
        }