Tailwind CSS : Is there a way to target next sibling?

Viewed 11644

I have a radio input with a label like below. input is hidden and label is used to make a visually appealing circle on which user can click.

<input id="choice-yes" type="radio" class="opacity-0 w-0 fixed"/>
<label for="choice-yes" class="transition  duration-500 bg-blue-300 hover:bg-blue-500 w-20 h-20 rounded-full mr-5 flex items-center align-middle justify-center">Yes</label>

When user clicked on the label input get checked. I'm trying to figure out how to target that, so I could give the label a different style.

This can be achieved in pure css using next sibling selector.

input[type="radio"]:checked + label {
  background-color: #bfb !important;
  border-color: #4c4 !important;
}

Is there something similar in tailwind.css that I could use instead?

6 Answers

Here's a complex variant I wrote for this purpose (tested with tailwindcss 2.0.1)

// tailwind.config.js

const plugin = require("tailwindcss/plugin");

const focusedSiblingPlugin = plugin(function ({ addVariant, e }) {
  addVariant("focused-sibling", ({ container }) => {
    container.walkRules((rule) => {
      rule.selector = `:focus + .focused-sibling\\:${rule.selector.slice(1)}`;
    });
  });
});

module.exports = {
  // ...
  plugins: [focusedSiblingPlugin],
  variants: {
    extend: {
      backgroundColor: ["focused-sibling"],
    },
  },
};

For those looking to implement this, since introduction of just-in-time mode (Tailwind CSS v2.1+) sibling selector variant is available.

There isn't anything built into Tailwind presently. The closest feature would be Pseudo-Class Variants of which there is a "checked" prefix. But that would only apply to the radio itself. In order to target siblings you'd need to write your own complex variant and then you could do something like

<input id="choice-yes" type="radio"/>
<label for="choice-yes" class="bg-gray-100 sibling-checked:bg-blue-500">Yes</label>

So, I've been wondering the same and since I've created my own variants since my Tailwind debut, I thought I could create a quick one for you.

My problem with previous answers is that the class is focused on the sibling. The class should be appended to the first item and used as such :

<input id="choice-yes" type="radio" class="nextOnChecked:bg-blue-500 nextOnChecked:border-blue-800"/>

The code for the variant should be something like :

const plugin = require("tailwindcss/plugin");

const nextOnChecked = plugin(function ({ addVariant, e }) {
  addVariant('nextOnChecked', ({ modifySelectors, separator }) => {
    modifySelectors(({ className }) => {
      return `.${e(`nextOnChecked${separator}${className}`)}:checked + *`;
    })
  });
});
module.exports = {
  variants: {
    extend:{
      border: ['nextOnChecked'],
      backgroundColor: ['nextOnChecked'],
    },
  },
  plugins: [
    nextOnChecked
  ],
};

This part .${e('nextOnChecked${separator}${className}')}:checked + * will be used, in the context of this example, as the following :

.nextOnChecked\:bg-blue-500:checked + *{
   background-color: ...;
}

That's how I build most of my variants, from the DOM that changes the state to the DOM that is being re-styled.

Since Tailwind v2.1 the JIT engine supports the peer variant, who works similarly to group, but is based on state of direct sibling. Ex.:

<input id="choice-yes" type="radio" class="peer opacity-0 w-0 fixed"/>

<label for="choice-yes" class="peer-checked:bg-[#bfb] border peer-checked:border-[#4c4] transition duration-500 bg-blue-300 hover:bg-blue-500 w-20 h-20 rounded-full mr-5 flex items-center align-middle justify-center">Yes</label>

Source: https://v2.tailwindcss.com/docs/just-in-time-mode#sibling-selector-variants

Related