Explain Codes LogoExplain Codes Logo

Css: Change parent on focus of child

html
responsive-design
performance
accessibility
Alex KataevbyAlex Kataev·Sep 14, 2024
TLDR

With CSS alone, parents can't be targeted based on a child's state. However, a clever workaround involves the use of a strategically placed checkbox and sibling selectors. When the hidden checkbox is focused and checked, it allows the following sibling to be styled via the sibling selector. Below demonstrates this method:

<div> <input type="checkbox" id="toggle" class="invisible"> <label for="toggle" class="child">Click me to teach parent new tricks</label> <div class="parent">I'm the parent and I'm learning new tricks!</div> </div>
.invisible { position: absolute; /* Hide and seek champion */ opacity: 0; } .invisible:focus + .child + .parent { /* Styling applied when checkbox is champion of hide and seek */ background-color: yellow; /* Fresh lemonade style in deck */ }

Tabbing into the label 'Click me to teach parent new tricks!' will give the checkbox the focus which subsequently changes the styling of its '.parent' sibling. This method exploits focus and structure to indirectly style a parent element.

Elevated experience with :focus-within

A more sophisticated option is :focus-within. When any child element gets focus, this pseudo-class applies the styles to the parent. This especially enhances user navigation in forms by highlighting the active fieldset or legend:

fieldset:focus-within { border: 2px solid blue; /* Royal blue for royal attention */ } legend:focus-within { color: green; /* Hear ye our green legend */ }

Information on :focus-within browser compatibility can be confirmed at caniuse.com. This feature elevates accessibility by indicating the active form element, sans JavaScript.

Living the old ways with JavaScript

If :focus-within doesn't cut the mustard for your project, JavaScript can lend a hand. It adds or subtracts a 'focused' class from your parent element based on the focus and blur events of the child:

let parent = document.querySelector('.parent'); let child = parent.querySelector('.child'); child.addEventListener('focus', () => parent.classList.add('focused')); /* Spread focus like butter */ child.addEventListener('blur', () => parent.classList.remove('focused')); /* Remove focus, no more butter */

Shape shifting from label to input

CSS lets you transition elements to give the illusion of a label morphing into a text input:

label { /* Currently undercover as ordinary text until focused */ } label:focus-within input[type="text"] { /* Code word activated, transform to text input */ }

Angular's view on the situation

If you're running the Angular show, ng-blur is a good guy to have around. It handles the graceful switch-back when an input loses focus, ensuring it reverts to its undercover label identity.

Editing strategy

The contenteditable attribute makes the switch between read-only and editable state as simple as a toggle, no need for transformation:

<label contenteditable="true">I can be edited. Click and see.</label>

Conversion challenges therefore become easier, but don't forget to weigh this against traditional form elements data management.

Comprehensive examples and considerations

Check out the interactive examples showcasing both the CSS :focus-within solution and the JavaScript approach on jsfiddle. Do remember that use of JavaScript may impact accessibility and performance when compared to a pure CSS solution.

An advanced trick with granular control uses :focus-within with the :not pseudo-class:

.parent:not(:focus-within) { /* Apply styles when children are not focused */ }

Always keep an eye on quirks with contenteditable attribute, such as unintended loss of focus, which could affect user experience.

Software development considerations

In complex scenarios, leverage state management libraries or frameworks that offer systematic solutions for handling state changes in response to user interactions.