Skip to content

Commit 1487104

Browse files
author
Sam Goody
committed
Added README
1 parent 651b8ee commit 1487104

1 file changed

Lines changed: 210 additions & 0 deletions

File tree

README.md

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# Tailwind-children <div style='font-size:0.6em'>Repeat elements without repeating styles<br> *.child, .sibling, and .descendant* variants for [TailwindCSS v3+](https://tailwindcss.com).</div>
2+
3+
# Installation
4+
5+
1. Install package:
6+
npm install tailwind-children --save
7+
8+
2. Add to tailwind.config.js
9+
10+
plugins: [
11+
require('tailwindcss-children'),
12+
]
13+
3. Build tailwind:
14+
npx tailwindcss -i ./src/input.css -o ./dist/output.css
15+
16+
# Usage: <div style='font-size:12px'>Pre-alpha. This <i>will</i> change!</div>
17+
18+
### child variant
19+
Set the styles in the parent and it will apply for all children with matching `child` class.
20+
Can use `children` or `child` aliases.
21+
Use `child-*` modifiers like `child-hover` to apply state and psuedo-classes to children elements:
22+
23+
<div class="overflow-hidden
24+
child:ring-white child-hover:shadow">
25+
<p class="child">I have a white ring...</p>
26+
<p class="child">And a shadow on hover!</p>
27+
</div>
28+
29+
### descendant variant
30+
Same usage, but includes non-direct descendants. Can use `descendant` or `heir` aliases
31+
32+
<div class="overflow-hidden
33+
heir:ring-white heir-hover:shadow">
34+
<div>
35+
<p class="heir">I have a white ring...</p>
36+
</div>
37+
<div>
38+
<p class="heir">And a shadow on hover!</p>
39+
</div>
40+
</div>
41+
42+
### sibling variant
43+
Same basic usage, but is applied to first of the repeating elements.
44+
Styles must be applied twice - once for itself and once for siblings with `sibling:` variant. (This has *some* duplication, but has an advantage that the styles are applied directly to the affected element and not to the parent.)
45+
46+
<div>
47+
<p class="
48+
ring-white hover:shadow
49+
sibling:ring-white sibling-hover:shadow">I have a white ring...</p>
50+
<p class="sibling">And a shadow on hover!</p>
51+
</div>
52+
53+
# Rationale
54+
55+
TailwindCSS is a GREAT utility-first CSS framework. Instead of inline styles (`<p style='display:block'>`) or opinionated predefined classes (`<button class='btn'>`) you have classes that replace and enhance the inline styles (`<p class='block'>`).
56+
57+
Its biggest issue is that it is (to quote them) "ugly". Your page gets littered with hundreds or thousands of classes.
58+
That ugliness is justified though, and once you start using TW you will never go back.
59+
60+
But there is one case where the ugliness is not just extreme, it also slows dev, adds complexity and introduces errors. It is such an issue, that it is referred to again and again in the official docs, [has a page to itself](https://tailwindcss.com/docs/reusing-styles) - and the suggested solutions are pretty poor; use an editor plugin or rely on JS.
61+
62+
The issue is that of repeating elements (such as `<li>'s`) that use the same styles.
63+
And its an issue which is surprising, as Tailwind's class based nature should make it really easy to fix.
64+
65+
This, then, is an attempt to solve the issue of reusing styles through a plugin, and maybe @adam will see this and make it official :)
66+
67+
### The Issue
68+
69+
To copy the example loosely from https://tailwindcss.com/docs/reusing-styles.
70+
Let's say you want to experiment with adding a shadow to all your `<img>s`.
71+
Manually copying it in each one is slowly and buggy. What to do?
72+
73+
<div class="mt-3 flex -space-x-2 overflow-hidden">
74+
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white hover:shadow" src="/img0.jpg" alt=""/>
75+
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white hover:shadow" src="/img1.jpg" alt=""/>
76+
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white hover:shadow" src="/img2.jpg" alt=""/>
77+
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white hover:shadow" src="/img3.jpg" alt=""/>
78+
<img class="inline-block h-12 w-12 rounded-full ring-2 ring-white hover:shadow" src="/img4.jpg" alt=""/>
79+
</div>
80+
81+
### A Proper Solution
82+
83+
Use `heir`, `child`, or `sibling` variants to target the respective elements (see usage above).
84+
85+
<div class="mt-3 flex -space-x-2 overflow-hidden
86+
child:inline-block child:h-12 child:w-12 child:rounded-full child:ring-2 child:ring-white child-hover:shadow">
87+
<img class="child" src="/img0.jpg" alt=""/>
88+
<img class="child" src="/img1.jpg" alt=""/>
89+
<img class="child" src="/img2.jpg" alt=""/>
90+
<img class="child" src="/img3.jpg" alt=""/>
91+
<img class="child" src="/img4.jpg" alt=""/>
92+
</div>
93+
94+
Isn't that nice?
95+
96+
### Perhaps, a better solution for sibling (not implemented)
97+
98+
Add class `.siblings` to the first element, and that will set up a rule `.siblings ~ *` to apply the same rules to all of the siblings.
99+
100+
This will make it simple to experiment, easy to understand, is clean and is DRY. FTW!
101+
```
102+
<div class="mt-3 flex -space-x-2 overflow-hidden">
103+
<img class="siblings inline-block h-12 w-12 rounded-full ring-2 ring-white hover:shadow" src="/img0.jpg" alt=""/>
104+
<img src="/img1.jpg" alt=""/>
105+
<img src="/img2.jpg" alt=""/>
106+
<img src="/img3.jpg" alt=""/>
107+
<img src="/img4.jpg" alt=""/>
108+
</div>
109+
```
110+
111+
Even better, we can have `siblings-of-type` to have it only apply said classes to peer elements with same tag.
112+
Admittedly, I do not know of any similar existing TW rule, but maybe it is just a matter of no need.
113+
114+
### Perhaps, a better solution for children (non-standard, not implemented)
115+
116+
Tailwind doesn't use other custom attributes, but I don't see why they shouldn't. CSS can handle any selectors, and we can prefix with tw- if we worry about conflict.
117+
118+
We can therefore create a children attribute with what ought to be applied to the children, and that would readable and DRY.
119+
120+
<div class="mt-3 flex -space-x-2 overflow-hidden"
121+
children="siblings inline-block h-12 w-12 rounded-full ring-2 ring-white hover:shadow"
122+
>
123+
<img src="/img0.jpg" alt=""/>
124+
<img src="/img1.jpg" alt=""/>
125+
<img src="/img2.jpg" alt=""/>
126+
<img src="/img3.jpg" alt=""/>
127+
<img src="/img4.jpg" alt=""/>
128+
</div>
129+
130+
This would make a rather awkward css rule, but not one that affects the dev or the user:
131+
`[children="siblings inline-block h-12 w-12 rounded-full ring-2 ring-white hover:shadow"] > * { ... } `
132+
133+
To be sure, I think that Tailwind should offer this for all psuedo-classes:
134+
135+
<div class="block"
136+
tw-after="content-['wow'] text-white">...
137+
</div>
138+
139+
And it is my hope that this plugin might be a foray into such usage!
140+
141+
142+
# Design Decision and Implementation
143+
144+
Like every good project, Tailwind has a consistent style, and we should be consistent with it.
145+
Here are examples where a TW class effects another element:
146+
147+
<body class="dark">
148+
<p class="dark:shadow">p has shadow when dark theme enabled</p>
149+
</body>
150+
151+
<input class="peer">
152+
<p class="peer-hover:shadow">p has shadow when hovering on input</p>
153+
154+
<div class="group">
155+
<p class="group-hover:shadow">p has shadow when hovering over div</p>
156+
</div>
157+
158+
In each of these examples,
159+
- we have the class on both the "calling" and "receiving" elements,
160+
- psuedo-classes are applied as `variant-*`, eg. `peer-hover`.
161+
162+
Let's see how that works out for us:
163+
164+
1. When declaring a state, we use the form `child-hover:shadow` with a dash between child and hover.
165+
- This differs from `child:hover:shadow`, used by [tailwindcss-children] (and IMO more intuitive)
166+
- It also differs from `hover:child:shadow` used by the official [@tailwindcss/typography] plugin.
167+
2. The rules only apply to children that have the matching 'child/sibling/etc' class.
168+
To demonstrate, if wanted only one of two children to match, here are several options.
169+
a. Require elements to "opt-in" with a "child" class
170+
```
171+
<div class="child:shadow">
172+
<p class="child">Shadow</p>
173+
<p>No Shadow</p>
174+
</div>
175+
```
176+
b. Apply style to all children, and allow children to override rules as needed.
177+
```
178+
<div class="child:shadow">
179+
<p>Shadow</p>
180+
<p class="drop-shadow-none">No Shadow</p>
181+
</div>
182+
```
183+
b. Offer a no-child class that tells it to not inherit
184+
```
185+
<div class="child:shadow">
186+
<p>Shadow</p>
187+
<p class="no-child">No Shadow</p>
188+
</div>
189+
```
190+
c. Only apply inheritance to element whose type is passed in. (Either `child-span` or `child-['span']`)
191+
```
192+
<div class="child-span:shadow">
193+
<span>Shadow</span>
194+
<p>No Shadow</p>
195+
</div>
196+
```
197+
[tailwind-child] uses method c, and [@tailwindcss/typography] supports methods b, c and d.
198+
In this version, we are still trying to be close-minded tw style, but will probably eventually switch to mimic typography.
199+
3. No using a class to copy other classes. Excludes the "better sibling solution" above.
200+
The idea was to set a flag that the styles and events that applied to the first should be applied to all siblings. Eventually, I do hope to implement this, so that it can be ignored by purists.
201+
4. No custom attributes, which excludes the "better children solution" above.
202+
I might eventually implement it, even though it is not a tailwind style rule at all. Feel free to not use.
203+
204+
# Contributing
205+
206+
Please open issues, file bug reports, give me your opinions on variant names, default styles and behaviors, and whatever else you can think of. There are a lot of good things input can add!
207+
208+
[tailwindcss-children]: https://github.com/benface/tailwindcss-children
209+
[@tailwindcss/typography]: https://tailwindcss.com/docs/typography-plugin
210+
[tailwind-child]: https://github.com/racha/tailwind-child

0 commit comments

Comments
 (0)