CSS: Change parent on focus of child
Asked Answered
T

5

177

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

Troyes answered 18/6, 2014 at 13:42 Comment(5)
javascript is no option?Rivero
This can't be done using only CSS, you need to use js.Marijane
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.Troyes
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 developer.mozilla.org/en-US/docs/Web/CSS/…Priapic
see this #14403014 it is the same problemMispickel
A
480

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>
Aussie answered 14/8, 2017 at 12:35 Comment(3)
IE should kicked away. R.I.PFatma
Wow, I did not know about this pseudo-class, this cleaned up my code a lot! ThanksAgar
This was not possible many years back! What a time to be aliveRevenuer
D
3

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.

Dylandylana answered 18/6, 2014 at 13:48 Comment(3)
Thanks for your answer. I added an edit regarding the reason for my question: I wanted to switch between the label and the input on focus/blur, and was having some issues doing this in Angular.Troyes
This is not vanilla JS, this is using jQuery.Karlotte
DV - Not JS and OP didn't ask for jQuery.Vermont
C
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;
}
Carlson answered 18/6, 2014 at 15:23 Comment(1)
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: #24289766, if you're interested.Troyes
C
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>
Carlson answered 18/6, 2014 at 15:37 Comment(1)
Useful, to be sure. Unfortunately, our client base requires the use of non-HTML5-compliant browsers.Troyes
F
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;
}
Furan answered 8/12, 2021 at 15:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.