What is the proper way in Tailwind to toggle a UI state? - tailwind-css

I'm a complete Tailwind css newbie and am playing with it in a small project.
What is the idiomatic way to toggle the UI state of a tab? Here are a couple tabs taken straight from the Tailwind website:
<nav class="-mb-px flex space-x-8" aria-label="Tabs">
<a class="border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm">
Tab 1
</a>
<a class="border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm">
Tab 2
</a>
<a class="border-indigo-500 text-indigo-600 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm">
Tab 3
</a>
</nav>
As you can see, Tab 3 is the "selected" state. What if I want to change selection to Tab 1. I'd have to swap a bunch of the utility classes (border-indigo-500 into border-transparent, etc.).
With vanilla CSS, you might define a css class called .selected that would override a normal tab's css and toggle that class on the html element, but I don't think that's the idiomatic way that tailwind recommends here.
Sorry if this is a super newbie question. Thanks.

For this, you can maintain three variables.
One that contains the selected tab value:
let selectedTab = "tab1"
And the other classnames of an active and non-active tab. Something like this:
const active = "border-indigo-500 text-indigo-600 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"
const nonActive = "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm"
Based on the click you change the value of the selected tab to its respective tab value and change the className of the HTML according to it.
Your HTML will look something like this
<nav class="-mb-px flex space-x-8" aria-label="Tabs">
<a class={selectedTab === "tab1" ? active : nonActive}> Tab 1 </a>
<a class={selectedTab === "tab2" ? active : nonActive}> Tab 2 </a>
<a class={selectedTab === "tab3" ? active : nonActive}> Tab 3 </a>
</nav>

Related

why is the color of this button leaking

In a vuejs app and using tailwindcss, I have a strange behaviour on my button:
this is the template code:
<div
:class=" [ bubbled ? 'text-vert' : 'text-grisee' ] "
#click = "togglebubbled()"
class="mt-6"
>
<FontAwesome icon="soap" class="lg:text-lg mr-4 lg:mr-0" />
<span class="ml-2" >Rappel mois prochain</span>
</div>
<div class="w-fit m-auto">
<FormButton :disabled="disabled">Envoyer</FormButton>
</div>
And the FormButton template :
<div>
<button
type="submit"
class="mt-6 px-5 py-3 drop-shadow-2xl hover:drop-shadow-none transition ease-in-out duration-300 rounded leading-snug whitespace-nowrap text-base font-semibold text-blanc"
:class="[disabled ? 'bg-grisee' : 'bg-bleulfdm hover:bg-marron']"
:disabled="disabled"
>
<slot></slot>
</button>
</div>
I have no explanation or solution for this effect, which is flickering, sometimes showing button correctly, sometimes leaking

Css pseudo-class 'after' not working with tailwindcss

I'm trying to recreate this with tailwindcss however when I implement this the hover effect is not working.
export default Home(){
return(
<a
href={item.href}
className="px-3 py-2 text-sm font-medium after:origin-center after:scale-x-0 after:border-b-2 after:transition-all after:duration-500 after:ease-in-out after:content-none hover:after:scale-x-100 hover:after:border-white"
aria-current="current item"
>
Item name
</a>
)
}
I created a working example using Tailwind following your desired result.
You can check the live demo here: stackblitz
The environment is installed following Tailwind official guide.
Hope this will help!
Example:
<div className="flex flex-col gap-6 justify-center items-center">
<a
href="#"
className="inline-block text-4xl text-slate-400 uppercase visited:text-slate-400 hover:text-slate-400 after:block after:origin-center after:scale-x-0 after:border-b-4 after:transition-all after:duration-500 after:ease-in-out hover:after:scale-x-100 hover:after:border-sky-500"
aria-current="current item"
>
Hover effect center
</a>
<a
href="#"
className="inline-block text-4xl text-slate-400 uppercase visited:text-slate-400 hover:text-slate-400 after:block after:origin-left after:scale-x-0 after:border-b-4 after:transition-all after:duration-500 after:ease-in-out hover:after:scale-x-100 hover:after:border-sky-500"
aria-current="current item"
>
Hover effect left
</a>
<a
href="#"
className="inline-block text-4xl text-slate-400 uppercase visited:text-slate-400 hover:text-slate-400 after:block after:origin-right after:scale-x-0 after:border-b-4 after:transition-all after:duration-500 after:ease-in-out hover:after:scale-x-100 hover:after:border-sky-500"
aria-current="current item"
>
Hover effect right
</a>
</div>

How to focus a div tag with a tailwind?

I'm using tailwind and Vue to make some reusable toggle component. Border of component is gray color, but plan is when I click on component, border will be red like on a image below (I'm using/trying using focus).
Problem is because I can use focus just on input and button, but I need focus on div tag
I have one div, inside is two paragraph and one input (type:checkbox). I tried with tabindex and it doesn't work, when I click in checkbox or input field (gray button) it doesn't focus. Only focuses when I click inside a component but not in checkbox field.
Code is
<template>
<div>
<div tabindex="1"
class="relative border border-gray-300 px-10 max-w-md mx-auto my-2 cursor-pointer rounded-lg px-5 py-4 rounded-lg border bg-white transition duration-150
ease-in-out placeholder:text-zinc-400 hover:bg-zinc-100 focus:border-transparent
focus:outline-none focus:ring disabled:opacity-50 motion-reduce:transition-none
dark:bg-zinc-900 dark:placeholder:text-zinc-500 dark:hover:bg-zinc-800" :class="[ error
? 'border-red-500 caret-red-500 focus:ring-red-500/50'
: 'border-zinc-300 caret-primary focus:ring-primary/50 dark:border-zinc-600 dark:focus:border-transparent',
]"
>
<div class="flex justify-between">
<div>
<h1 class="text-md font-semibold text-black">
{{ titleToggle }}
</h1>
<p class="inline text-md text-gray-500">
{{ subtitleToggle }}
</p>
</div>
<label class="switch my-auto">
<input
:value="toggleSwitch"
v-bind="$attrs" type="checkbox"
class="rounded-lg " :class="[
error
? 'border-red-500 caret-red-500 focus:ring-red-500/50'
: 'border-zinc-300 caret-primary focus:ring-primary/50
dark:border-zinc-600 dark:focus:border-transparent',]" #click="updateInput"
>
<span :class="[toggleSwitch ? 'bg-red-500 border-red-500' : 'bg-gray-300 border-gray-300',
]" class="slider round absolute cursor-pointer inset-0 border rounded-full"
/>
</label>
</div>
</div>
</div>
</template>
Is anyone have advice, or maybe different way how to do it ?
I don't really understand your question, but you may have a look at this from the tailwind documentation :
focus-within (:focus-within) : Style an element when it or one of its descendants has focus using the focus-within modifier:
<div class="focus-within:shadow-lg ...">
<input type="text" />
</div>
https://tailwindcss.com/docs/hover-focus-and-other-states#focus

Tailwind Alpine.js hide show menu with checkbox checked

I am using Alpine.js in my new Tailwind project and now I am stuck, while it has been working great.
I made a hamburger menu icon with a checkbox and now I want the menu to actually show up.
Not really getting any closer from reading the Alpine documentation, it has a lot of info on buttons but not on checkboxes.
I want to initially not show the menu, check the checkbox ie. press the hamburger menu icon and show the mobile menu. Clicking the icon again ie. unchecking the checkbox, hides the menu again.
My code now:
<label for="check-menu" class="flex flex-col cursor-pointer w-70px">
<input type="checkbox" id="check-menu" class="hidden" x-model="show" />
<span class="duration-[400ms] bg-white rounded-md w-full h-7px mx-0 my-7px hamburger"></span>
<span class="duration-[400ms] bg-white rounded-md w-full h-7px mx-0 my-7px hamburger"></span>
<span class="duration-[400ms] bg-white rounded-md w-3/4 ml-25pc h-7px my-7px hamburger"></span>
</label>
<div x-text="show">
Menu on mobile
</div>
The site gives console errors and is not loading anymore..
I also tried the #click event with .self, not working as well (the mobile menu doesnt show).
Anyone has any clue how to make this happen?
You have to always mark an Alpine.js component with x-data directive and define the reactive variables there.
<div x-data="{show: false}">
<label for="check-menu" class="flex flex-col cursor-pointer w-70px">
<input type="checkbox" id="check-menu" class="hidden" x-model="show" />
<span class="duration-[400ms] bg-white rounded-md w-full h-7px mx-0 my-7px hamburger"></span>
<span class="duration-[400ms] bg-white rounded-md w-full h-7px mx-0 my-7px hamburger"></span>
<span class="duration-[400ms] bg-white rounded-md w-3/4 ml-25pc h-7px my-7px hamburger"></span>
</label>
<div x-show="show">
Menu on mobile
</div>
</div>

I'm trying to "draw" a circle using a span, sometimes work, sometimes doesn't

This puzzles me a lot. I'm writing a Laravel application, and I want to draw a circle besides a description. The circle must be either gray or yellow depending on a condition, so my code is:
...
<ul>
#foreach ($section->lessons as $lesson)
<li class="flex items-start mb-1">
<span class="inline-block w-4 h-4 mt-1 mr-2 {{ $lesson->complete ? 'bg-yellow-400' : 'bg-gray-500' }} rounded-full"></span>
<a
class="cursor-pointer"
wire:click="changeLesson({{ $lesson }})"
>{{ $lesson->name }}</a>
</li>
#endforeach
</ul>
...
This code works, no problem with it, but with the display. Check the span Tailwind classes: "inline-block w-4 h-4 mt-1 mr-2 bg-yellow-400 }} rounded-full", this should draw a perfect circle (w-4 h-4) right?
Now see what it displays:
As you can see, for the one line descriptions, the circle is perfect, but for the ones that have two lines, it becomes sort of an oval, and it moves the margin slightly to the left
Why this happens and how can I fix it?
You have a flex container so you don't need inline-block on the spans but flex is also the reason your long line span element is getting squashed.
A simple fix is to add flex-shrink-0 to those spans.
Here it is working on Tailwind Play https://play.tailwindcss.com/H0kZFOVNaX
<ul>
<li class="flex items-start mb-1">
<span class="w-4 h-4 mt-1 mr-2 bg-gray-500 rounded-full"></span>
<a
class="cursor-pointer"
wire:click="changeLesson({{ $lesson }})"
>Some regular sized content</a>
</li>
<li class="flex items-start mb-1">
<span class="w-4 h-4 flex-shrink-0 mt-1 mr-2 bg-gray-500 rounded-full"></span>
<a
class="cursor-pointer"
wire:click="changeLesson({{ $lesson }})"
>Some extra large XXXL sized content that has way too long of a title and can smash an inline element.</a>
</li>
</ul>

Resources