78

I have this html:

<div class="section">
   <div class="header">header</div>
   <div class="content">
      <div>sub contents 1</div>              
      <div>sub contents 2</div>
   </div>
</div>

I want to access the direct children of div with class "section" which would be divs with class: "header" and "content".

I know with css we can do: div.section > div

But how to do this using tailwindcss?

Manoj Singh
  • 1,911
  • 1
  • 20
  • 22

6 Answers6

251

In tailwind 3.1, you can use arbitrary values to target child elements.

<div class="[&>*]:p-4">...</div>
<div class="[&>p]:mt-0 ">...</div>

https://tailwindcss.com/blog/tailwindcss-v3-1#arbitrary-values-but-for-variants

phum
  • 2,511
  • 2
  • 9
  • 3
  • I would say that this should not be used at all. Why? Because if this is for example component as children you are changing styles of the component from different place that it have its own styles. It creates technical depth, it is hardly findable and I presume that this is not good practice at all. – Ernedar Aug 03 '22 at 08:17
  • 4
    I agree that if possible this solution should not be implemented, however, there are times when you can't access to style HTML directly(e.g. 3rd party script). It can be a pretty useful escape hatch when trying to style HTML you can’t directly change. – phum Aug 03 '22 at 09:52
  • 20
    Note that spaces for selecting descendants need to be replaced by underscores, e.g. `'[&_svg]:stroke-white'` instead of `'[& svg]:stroke-white'`. See https://tailwindcss.com/docs/hover-focus-and-other-states#using-arbitrary-variants – kca Sep 05 '22 at 10:32
  • 2
    @kca Consider adding this to the above answer. I was having trouble with exactly this. The answer should include your point. – sayandcode Oct 07 '22 at 17:54
  • https://play.tailwindcss.com/rq8YVDB3LG – Skaman Sam Apr 14 '23 at 02:25
87

I use these simple lines in tailwind.config.js to give me child and child-hover options.

plugins: [
    function ({ addVariant }) {
        addVariant('child', '& > *');
        addVariant('child-hover', '& > *:hover');
    }
],

Then use like this

<div class="child:text-gray-200 child-hover:text-blue-500">...</div>

Which will give every child a gray textcolor, and a blue one on hover.

See here for more information on adding variants using a plugin

For long, this was long the only way to do it. Since 4th of july 2022, Tailwind also added an ad-hoc approach to target specific elements. You can now use [&>*]:text-gray-200 or [&>*:hover]:text-blue-500 to mimic the above behaviour. See the answer of @phum for more info!

Willem Mulder
  • 12,974
  • 3
  • 37
  • 62
  • 7
    This was a lifesaver for me. If you're looking for an even more permissive version where the parent effects all children, you can utilize `& *` and `&:hover *` respectively. This came in handy for component development – Josh Frankel Apr 08 '22 at 16:14
  • How to achieve the same in browser using CDN? I tried doing `tailwind.config = { plugins: () => {...}}` but that is not working. – Srikanth Sharma Apr 24 '22 at 07:42
  • @SrikanthSharma Interesting; I did not know they had a CDN version. Looking at the documentation, it seems like they do actually support plugins in the CDN version (which would be a miracle in itself). Maybe you did not define plugins as an Array? – Willem Mulder Apr 25 '22 at 08:19
  • `:child` variant alone should suffice but `child:hover:...` becomes `:hover > *` and vise versa, which is weird since tailwind docs say that the variants are applied in the order they were given ... so `child-hover` is needed – Sodj May 11 '22 at 16:06
  • @Sodj You'll have to do `hover:child:` instead and it should work – Jeffrey Aug 20 '23 at 06:41
4

If you want to access the direct children of div with selector, please use @layer directive. see below:

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  div.section > div {
    @apply text-xl;
  }
}

https://tailwindcss.com/docs/adding-base-styles

GeckoTang
  • 2,697
  • 1
  • 16
  • 18
  • idk but this doesnt work for me `div.field_with_errors > label { @apply text-red-900; }` – buncis Aug 27 '22 at 04:44
  • note that the base layer should only contain the apps default styling of commonly used tags, and is not designed for specific use-case styling – Gabriel Petersson Nov 18 '22 at 12:23
1

This is currently not possible and probably won't be implemented soon.

Instead, I recommend using this plugin: https://github.com/benface/tailwindcss-children. Follow the README for further instructions.

Usage:

After you have installed the plugin and added it to your tailwind.config.js, you can access direct children by adding children:{your_style} to the parent class. If you for example would want to add p-4 to header and content, your code would look like this:

<div class="section children:p-4">
   <div class="header">header</div>
   <div class="content">
      <div>sub contents 1</div>              
      <div>sub contents 2</div>
   </div>
</div>
  • 1
    Your answer could be improved by providing an example of the solution and how it helps the OP. – Tyler2P Jan 25 '22 at 17:15
  • This is deprecated and doesn't work with tailwind 3.0 – Prav Apr 29 '22 at 18:43
  • 2
    There's a new library for Tailwind v3+: [tailwind-children](https://github.com/SamGoody/tailwind-children) – khaki Jun 26 '22 at 11:41
  • Can confirm, works for Tailwind 3+. Personally this is my preferred answer, since it allows us to mix existing variants along with the `child:` (and others) this one brings. – chamberlainpi Sep 20 '22 at 14:41
0

This is tailwind v1&v2 version of Willem Mulder's.

only change is variant name children instead of child

 plugin(function({ addVariant, e }) {

  addVariant('children', ({ modifySelectors, separator }) => {
    modifySelectors(({ className }) => {
      const newClass = e(`children${separator}${className}`);
      return [
        `.${newClass} > *`,
        // `.${newClass}:hover `,
      ].join(",");
    });
  });

  addVariant('children-first', ({ modifySelectors, separator }) => {
    modifySelectors(({ className }) => {
      const newClass = e(`children-first${separator}${className}`);
      return [
        `.${newClass} > *:first-child`,
      ].join(",");
    });
  });

}),

add variants for padding

variants: {
    padding: ['responsive', 'children', 'children-hover', 'children-first', ],
   
  },
scil
  • 169
  • 10
0

This is the best way that i found to write classes.
This can also work with things like hover,active,etc.
in svelte

  <div class=` 
{ classer("[&>button:hover]","bg-slate-500 scale-110") } 
{ classer("[&>button]","bg-slate-400 w-full my-2 py-2 rounded") }
` >

Ts function like

export function classer(selector:string, allclasses:string):string  {
  let classList = allclasses.split(" ")
  return classList.map((item) => selector+":" + item).join(" ")
}