Target every child except first in Tailwind

Last updated: 

So I can add a margin-top to all the list items except the first

<ul className="not-first:mt-20">
  <li>Without Margin</li>
  <li>With Margin</li>
  <li>With Margin the second</li>
</ul>

To get this working I added the following to my tailwind.config.js file, though the notFirst plugin function part could of course be out-sourced into a separate file.

// tailwind.config.js
const plugin = require("tailwindcss/plugin");

const notFirst = plugin(({ addVariant, e }) => {
  addVariant("not-first", ({ modifySelectors, separator }) => {
    modifySelectors(({ className }) => {
      const element = e(`not-first${separator}${className}`);
      return `.${element} > :not(:first-child)`;
    });
  });
});

module.exports = {
  plugins: [notFirst],
};

Note the > which is the child combinator to ensure it's only targeting the direct children and not children's-children

And alternative to :not(:first-child) would be to use the adjacent sibling combinator which works in CSS like so

ul > li + li {}

and in the Tailwind plugin you would rewrite the return statement in line 8 to

return `.${element} > * + *`;

More research can help find conventions

Then I stumbled upon Tailwinds space between utilities and divide utilities (to do the same thing with a border) via tailwindcss/discussions#2156.

So digging deeper helped me find that it's already possible and I like to stick to existing solutions wherever possible, if I don't "dislike" them for whatever reason 🤓

Why margin-top in the first place?

Ever since I stumbled upon (I think) this article (https://css-tricks.com/margin-bottom-margin-top/) I prefer to use margin-top over margin-bottom, though both work if you stick to one and/or keep well in mind of margin's collapse

More on the topic

Can Rau
Can Rau

Doing web-development since around 2000, building my digital garden with a mix of back-to-the-roots-use-the-platform and modern edge-rendered-client-side-magic tech 📻🚀

Living and working in Cusco, Perú 🦙