user23981346
user23981346

Reputation: 3

Using map to generate sibling classes in tailwind

I am using tailwind and react and nextjs to create a website. I am trying to utilize the check radio button trick to have a website display different content without javascript. I want to make the data structure easy to manage so I thought of using an array of objects like [{name: string, content: string}, ... ]. This is part of the tailwind documentation I was following: differentiating peers

I thought I could just replace the

class="peer/draft"

with

className={`peer/${item.name}`}`

given that it is wrapped inside array.map((item) => { ... }).

This is part of the tailwind documentation I was following: differentiating peers

The code generates the right thing since:

If I just use the pure html code that is compiled by nextjs and send to the client browser, the siblings play with peace.

but:

If I just let nextjs compile it and deliver it to the client browser, the same html code read by the client browser wouldn't react when a radio button is pressed!

This is my code including a data example:

export default function page() {
    const jobs = [
        {
            name: "walker",
            id: "wlk",
            conditions: "20 an hour",
            content: "walk and walk"
        },
        {
            name: "sitter",
            id: "sit",
            conditions: "20 an hour",
            content: "sit and sit"
        },
    ]

    return (
        <section id="careerHome">
            <div className="container grid md:grid-cols-2">
                {jobs.map((item) => {
                    return (
                        <div
                            key={item.id}
                            className="shadow-lg p-10 text-center capitalize flex-1 mt-6 rounded-md flex flex-col relative"
                        >
                            <h3>
                                {item.name}
                            </h3>
                            <input id={item.id} className={`peer/${item.id}`} type="radio" name={item.id} />
                            <b className="text-start">Learn More</b>
                            <div className="h-4"></div>
                            <input id={`${item.id}Close`} className={`peer/${item.id}Close`} type="radio" name={item.id} />
                            <b className="text-start">Close</b>
                            <div className={`hidden peer-checked/${item.id}:block absolute top-20 right-[10%]`}>
                                <p>{item.conditions}</p>
                            </div>
                            <div className={`hidden peer-checked/${item.id}:block`}>
                                <p>{item.content}</p>
                            </div>
                        </div>
                    )
                })}
            </div>
        </section>
    )
}

It is supposed to have two buttons for each block, one for opening and one for closing.

Is it possible to use generative functioning to assign tailwind classes?

I am sure this is not the prettiest way to do things so if this is not recommended please tell me more!

Upvotes: 0

Views: 232

Answers (1)

Wongjn
Wongjn

Reputation: 24303

As per the documentation:

The most important implication of how Tailwind extracts class names is that it will only find classes that exist as complete unbroken strings in your source files.

If you use string interpolation or concatenate partial class names together, Tailwind will not find them and therefore will not generate the corresponding CSS:

Don’t construct class names dynamically

<div class="text-{{ error ? 'red' : 'green' }}-600"></div>

In the example above, the strings text-red-600 and text-green-600 do not exist, so Tailwind will not generate those classes. Instead, make sure any class names you’re using exist in full:

Always use complete class names

<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>

Since it seems the peer element and its "dependents" are each separated by a parent <div> element and you are only really using one peer (peer/${item.id}Close is not used), you shouldn't need to use labelled peers:

function Page() {
  const jobs = [
    {
      name: 'walker',
      id: 'wlk',
      conditions: '20 an hour',
      content: 'walk and walk',
    },
    {
      name: 'sitter',
      id: 'sit',
      conditions: '20 an hour',
      content: 'sit and sit',
    },
  ];

  return (
    <section id="careerHome">
      <div className="container grid md:grid-cols-2">
        {jobs.map((item) => {
          return (
            <div
              key={item.id}
              className="shadow-lg p-10 text-center capitalize flex-1 mt-6 rounded-md flex flex-col relative"
            >
              <h3>{item.name}</h3>
              <input
                id={item.id}
                className="peer"
                type="radio"
                name={item.id}
              />
              <b className="text-start">Learn More</b>
              <div className="h-4"></div>
              <input id={`${item.id}Close`} type="radio" name={item.id} />
              <b className="text-start">Close</b>
              <div className="hidden peer-checked:block absolute top-20 right-[10%]">
                <p>{item.conditions}</p>
              </div>
              <div className="hidden peer-checked:block">
                <p>{item.content}</p>
              </div>
            </div>
          );
        })}
      </div>
    </section>
  );
}

ReactDOM.createRoot(document.getElementById('app')).render(<Page/>);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js" integrity="sha512-QVs8Lo43F9lSuBykadDb0oSXDL/BbZ588urWVCRwSIoewQv/Ewg1f84mK3U790bZ0FfhFa1YSQUmIhG+pIRKeg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js" integrity="sha512-6a1107rTlA4gYpgHAqbwLAtxmWipBdJFcq8y5S/aTge3Bp+VAklABm2LO+Kg51vOWR9JMZq1Ovjl5tpluNpTeQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.tailwindcss.com/3.4.3"></script>

<div id="app"></div>

Upvotes: 0

Related Questions