Tailwind toggle input - css

I have the following toggle input which comes from:
<div className="relative">
<input
data-testid="toggle-input-checkbox"
onChange={handleOnChange}
id={id}
type="checkbox"
className="sr-only"
checked={isChecked}
/>
<div className="base w-9 h-3.5 bg-grey-6 rounded-full shadow-inner" />
<div className="dot bg-white absolute w-5 h-5 rounded-full shadow -left-1 -top-1 transition" />
</div>
and toggle.css:
input:checked ~ .base {
background-color: #46e18c;
}
input:checked ~ .dot {
transform: translateX(100%);
}
is there a way in Tailwind to avoid using custom classes to achieve the desired style?

Use peer modifier, like that:
// Add `peer` to the element which state you want to track
<input type="checkbox" checked class="peer" />
// Then use `peer-*` modifiers on the target element which style you want to change
<div class="peer-checked:text-red-500">Sibling</div>
Playground link
More info in the docs as always

Related

Tailwind CSS: change parent label style when a child checkbox is checked

I want to add the add a border to my checkbox container when the checkbox is checked.
Currently, I have this:
<label
htmlFor="choose-me"
className=
'flex w-fit items-center justify-evely p-3 border-2 border-grey-4 text-grey-8
peer-checked:bg-light-indigo peer-checked:text-medium-indigo peer-checked:border-medium-indigo'>
<input type="checkbox" id="choose-me" className="peer mr-3 " />
Check me
</label>
I want something like the below:
However, I am unable to change the label styles when I put my input inside the label.
A CSS-only solution would be to use the :has pseudo-selector (note: not supported yet in Firefox). This would apply the classes only if the label wraps a checkbox which has been checked.
index.css
#tailwind base;
#tailwind components;
#tailwind utilities;
#layer components {
.checkbox-label:has(input:checked) {
#apply border-blue-800 bg-blue-400 text-blue-800;
}
}
Your JSX: (with the unused classes stripped out)
<label className="checkbox-label justify-evely border-grey-4 text-grey-8 flex w-fit items-center gap-x-2 border-2 p-3">
<input type="checkbox" id="choose-me" />
Check me
</label>
You can test it here: https://play.tailwindcss.com/zidP4zm2Pq
The list of browsers supporting :has: https://developer.mozilla.org/en-US/docs/Web/CSS/:has#browser_compatibility
use useState for handle active state:
const [isactive,setActive] = useState(false)
in JSX:
<label
onClick={()=>setActive(isactive?false:true)}
className= {`${isactive?'active-style':'normal-style'} extra-style-classes`}
>
<input type="checkbox" id="choose-me" className= {`${isactive?'active-style':'normal-style'} extra-style-classes`} />
Check me
</label>
First off, it's important to remember that the peer functionality in tailwind doesn't target parents (which is what you currently have). You can only target elements that are next to one another.
Additionally, because of how the CSS :peer combinator works you can only target previous components, meaning the checkbox MUST come before the peer who's state you want to affect when the checkbox is checked.
<label
htmlFor="choose-me"
class=
'flex w-fit items-center justify-evely p-3 text-grey-8 relative'
>
<input type="checkbox" id="choose-me" class="peer mr-3 relative z-10" />
<div class="absolute inset-0 border-2 border-grey-4 peer-checked:bg-indigo-200 peer-checked:text-indigo-800 peer-checked:border-indigo-800 peer-checked:block z-0"></div>
<span class="relative z-10">Check me</span>
</label>
Here's an example that works using pure tailwind/css, assuming you don't want to handle the state in your react component, as per #Vikesir's comment (though that was my first thought as well and it's a good idea).
You'll notice I'm fudging in an empty div and using that to simulate the background and border changing. I also wrapped the label text in a span to make sure I could change it's z-index so that both the checkbox and the text were visible above the div that handles the state change.
EDIT:
Here is a version using a pseudo-element built off of the span holding the label text if you don't want the empty div in your code:
<label
htmlFor="choose-me"
class=
'flex w-fit items-center justify-evely text-grey-8 relative'
>
<input type="checkbox" id="choose-me" class="peer mr-3 absolute left-2.5 z-20" />
<span class="relative z-10 inset-0 py-3 pr-3 pl-8 before:-z-10 before:content-[''] before:absolute before:inset-0 before:h-full before:w-full before:border-2 before:border-grey-4 peer-checked:before:bg-indigo-200 peer-checked:before:text-indigo-800 peer-checked:before:border-indigo-800 peer-checked:before:block">Check me</span>
</label>

How to add specific styles to className in Tailwind

I am passing a style to a checkbox when it is checked, but I do it in my tailwind.css file.
I am wondering if it is possible somehow to do it in className inline, because I do not want really to add many global styles to tailwind.css.
So here's the component so whenever I check it adds an SVG instead of default checkbox:
<input
key={color}
type="checkbox"
className="peer hidden input:checked"
name="checkbox-colors"
checked={isChecked === color}
value={color}
onClick={(e) => {
handleColorChange(e.currentTarget.value);
}}
readOnly
/>
<div className="h-full w-full flex justify-center items-center">
<CheckIcon className="hidden" />
</div>
and the styles are these:
input:checked + div svg {
#apply block;
}
so if it is possible somehow to use it in input className="peer hidden input:checked..."
Actually found a way around of using cn of #classNames and doing it like that:
<div className="h-full w-full flex justify-center items-center">
<CheckIcon
className={cn({
hidden: isChecked !== color,
})}
/>
</div>
and works like a charm!

Styling file input: Shadow of "choose file" is cut off

I tried to style file input button to look kind of like all buttons in my app. I use tailwind for styling.
Below example of button on hover:
The shadow is not hidden or cut off. But if I try to use the same style on file input - it looks like this:
The shadow is cut off. Looks like there is an overflow hidden but there isn't.
File input code:
<div className="flex flex-col gap-y-2 overflow-visible">
<label htmlFor="art_cover">Art cover</label>
<input
type="file"
name="art_cover"
id="art_cover"
onChange={({ currentTarget }: ChangeEvent<HTMLInputElement>) => {
currentTarget.files && formik.setFieldValue('art_cover', currentTarget.files[0]);
}}
className="text-gray-400 file:border-solid file:btn-style file:text-primary-light file:mr-3"
/>
</div>
Tailwind reused style that I use for buttons:
.btn-style {
#apply rounded-full bg-transparent border-2 border-primary-accent font-bold px-4 md:px-5 py-1 md:py-1.5 cursor-pointer
transition text-center text-sm md:text-base hover:bg-primary-accent hover:text-secondary-dark hover:shadow-accent;
}
.shadow-accent {
#apply drop-shadow-[0_0_15px_rgba(78,255,166,0.3)];
}
Fixed by changing my input implementation using this answer.
<div className="flex flex-col gap-y-2">
<label htmlFor="art_cover">Art cover</label>
<label htmlFor="art_cover" className="flex items-center">
<div className="btn-style text-primary-light mr-3">Choose file</div>
<p className="text-gray-400">{formik.values.art_cover === undefined ? 'No file chosen' : formik.values.art_cover['name']}</p>
</label>
<input
type="file"
name="art_cover"
id="art_cover"
onChange={({ currentTarget }: ChangeEvent<HTMLInputElement>) => {
currentTarget.files && formik.setFieldValue('art_cover', currentTarget.files[0]);
}}
className="hidden"
/>
</div>
Works like a charm

React : set style of a children based on the prop of a parent

I have below code
<span className="item-toggle" onClick={toggleChecked}>
<Checkbox toggle checked={checked} data-togglecolor={toggleColor}/>
</span>
That renders to
<span class="item-toggle">
<div class="ui checked fitted toggle checkbox" data-togglecolor="#9cd3dd">
<input class="hidden" readonly="" tabindex="0" type="checkbox" value="" checked="">
<label></label>
</div>
</span>
The Checkbox component is part of the Semantic UI React. I would like to use the value of the data-togglecolor to style my input :
.ui.toggle.checkbox input:checked ~ label:before {
background-color: XXX;
}
I could ofcourse hardcode it like below in my CSS
.ui.toggle.checkbox[data-togglecolor="#9cd3dd"] input:checked ~ label:before {
background-color: #9cd3dd;
}
But I was wondering how I could achieve this dynamically.
Thanks !
Do you use styled-components ?
If so, you could override the Checkbox component to pass the background-colour to its child, just like this :
const Checkbox = styled(ImportedCheckbox)`
input {
background-color: ${p => p['data-togglecolor']};
}
`
You can't access props in your CSS files unless you used something like styled-components or something related, what you can do is add a style attribute to your checkbox
<div class="ui checked fitted toggle checkbox" style={{backgroundColor: this.props.yourcolorprophere}}></div>

not of nth child selector not working in sass

I am trying to apply certain styles to all items in list besides the first child. I think I set up the sass correctly, however the style is not being applied currently.
html
<div class="list">
<div *ngFor="let item of data; index as i; first as isFirst; last as isLast"class="list-item">
<input class="radio" name="radio" type="radio" />
<label for="radio1">Buttom</label>
</div>
</div>
sass
.list label:not(:nth-of-type(1))::before{
background-color:blue;
}
You can achieve this doing by all the items bg blue and the first one's bg to white or whatever your background is.
<div class="list">
<div *ngFor="let item of data; let i=index" [class.first]="i === 0">
<input class="radio" name="radio" type="radio" />
<label for="radio1" class="lbl">{{item.name}}</label>
and your css should be like this:
label {
background-color:blue;
}
.first label {
background-color: #fff;
}
I assume your data is like that:
data = [
{name: "car"},
{name: "truck"},
{name: "bike"}
]
This is working example
If you mean selecting all .list-item except the first one, the CSS will be like:
.list-item:not(:nth-of-type(1))::before {
content: '';
background-color:blue;
}
Since you are using pseudo element ::before, you may want to use content: '' to specify some content, otherwise background-color will has no effect.

Resources