Hello I need a small help I want to hide button background and I am unable to apply flex which wraps the items contained in a container in which it is applied into single line
My html code:
import {
GlobeIcon,
HomeIcon
}from '#heroicons/react/outline'
function Sidebar(){
return (
<div>
<button className='flex items-center space-x-2 hover:text-white'>
<HomeIcon className = 'h-5 w- 5'/>
<p1>Home</p1>
</button>
<button className='flex items-center space-x-2 hover:text-white'>
<GlobeIcon className = 'h-5 w- 5'/>
<p1>Explore</p1>
</button>
</div>
)
}
export default Sidebar;
I want my page to look like
But my actual page is shwing like
Anybody could help me with it
Related
The problem:
class="hover:bg-blue-400 hover:-translate-y-2 hover:-translate-x-2 hover:scale-110 hover:shadow-2xl hover:shadow-blue-400 hover:text-white"
here you see, there is the same prefix repetition.
hover:foo hover:bar hover:hello hover:world hover:something hover:another
I want to know if is there a way to not write multiple times the hover: prefix?
The idea:
is do something like:
hover:(class class class class class)
with brackets or something like that, so all the classes inside the () will be like one class and automatically added to the hover:
I think this idea there is in tailwind but I don't know the syntax for that.
if is possible this solution needs to work also with all the other prefixes
simple example demo:
// not important, only for deleting the console.warn()
console.clear();
<script src="https://cdn.tailwindcss.com"></script>
<body class="flex h-screen">
<button class="m-auto p-4 rounded-md bg-blue-200 transition hover:bg-blue-400 hover:-translate-y-2 hover:-translate-x-2 hover:scale-110 hover:shadow-2xl hover:shadow-blue-400 hover:text-white">
hello world
</button>
</body>
I saw all the docs, that is not talking about this concept: https://tailwindcss.com/docs/hover-focus-and-other-states#hover-focus-and-active
if there is someone experienced in this thing, it will be helpful!
like he said #diego in the comment, this is technically not possible with tailwind only.
tailwind framework alternative
maybe you use a tailwind framework like windiCSS https://windicss.org/features/variant-groups.html
that have this functionality:
<div class="hover:(bg-gray-400 font-medium) bg-white font-light"/>
javascript vanilla (simple script)
want tailwind only?
so I think that maybe we can create a simple JS script to solve this problem.
twHover();
function twHover() {
// get only the elements that have the hover attribute
let hoverEls = document.querySelectorAll("[data-hover]");
// loop through the elements that have the hover attribute
hoverEls.forEach((el) => {
// we get the string inside the attribute
// and then make it into a array
let twHoverClasses = `${el.dataset.hover}`.split(" ");
// loop through the classes inside the element's attributes
twHoverClasses.forEach((className) => {
// add the class for you `hover:className`
el.classList.add(`hover:${className}`);
});
});
}
<script src="https://cdn.tailwindcss.com"></script>
<body class="flex h-screen">
<!-- original -->
<button class="m-auto p-4 rounded-md bg-blue-200 transition hover:bg-blue-400 hover:-translate-y-2 hover:-translate-x-2 hover:scale-110 hover:shadow-2xl hover:shadow-blue-40 hover:text-white">original</button>
<!-- with script -->
<button data-hover="bg-blue-400 -translate-y-2 -translate-x-2 scale-110 shadow-2xl shadow-blue-40 text-white" class="m-auto p-4 rounded-md bg-blue-200 transition">with script</button>
</body>
want more from the JS script?
also :focus, :lg, :sm, and so on.
use this:
// this can be any preudo class that tailwind can have
twPseudo("focus");
// if there is nothing as parameter, we use hover
twPseudo();
function twPseudo(pseudo = "hover") {
// get only the elements that have the hover attribute
let hoverEls = document.querySelectorAll(`[data-${pseudo}]`);
// loop through the elements that have the hover attribute
hoverEls.forEach((el) => {
// we get the string inside the attribute
// and then make it into a array
let twHoverClasses = `${el.dataset[pseudo]}`.split(" ");
// loop through the classes inside the element's attributes
twHoverClasses.forEach((className) => {
// add the class for you `hover:className`
el.classList.add(`${pseudo}:${className}`);
});
});
}
<script src="https://cdn.tailwindcss.com"></script>
<body class="grid grid-cols-2 place-items-center h-screen">
<!-- original -->
<div>
<h2 class="text-3xl font-bold text-blue-500 mb-4">original</h2>
<!-- hover -->
<button class="m-auto p-4 rounded-md bg-blue-200 transition hover:bg-blue-400 hover:-translate-y-2 hover:-translate-x-2 hover:scale-110 hover:shadow-2xl hover:shadow-blue-40 hover:text-white">hover</button>
<!-- focus -->
<button class="m-auto p-4 rounded-md bg-blue-200 transition focus:bg-blue-400 focus:-translate-y-2 focus:-translate-x-2 focus:scale-110 focus:shadow-2xl focus:shadow-blue-40 focus:text-white">focus</button>
</div>
<!-- with script -->
<div>
<h2 class="text-3xl font-bold text-blue-500 mb-4">with script</h2>
<!-- hover -->
<button data-hover="bg-blue-400 -translate-y-2 -translate-x-2 scale-110 shadow-2xl shadow-blue-40 text-white" class="m-auto p-4 rounded-md bg-blue-200 transition">hover</button>
<!-- focus -->
<button data-focus="bg-blue-400 -translate-y-2 -translate-x-2 scale-110 shadow-2xl shadow-blue-40 text-white" class="m-auto p-4 rounded-md bg-blue-200 transition">focus</button>
</div>
</body>
also make sure to put the script code at the end of the page or inside a DomContentLoaded event
advantages:
less repetitive characters to type
more than 25 chars saved (only in your example)
multiple line attribute
As you can see you can write your classes in one line,
and the hover logic in another line. making it easy to debug.
works out of the box.
just copy and paste, and call the function.
with the correct parameter (focus, sm, lg, xl, 2xl) or without any parameter (will be hover)
// just call it at the end of the page
twPseudo();
You can just create a new class in a <style> block in your page or template. And then use #apply to use the needed tailwind classes. Like:
<style>
.mybutton {
#apply m-auto p-4 rounded-md bg-blue-200 transition
}
.mybutton:hover {
#apply bg-blue-400 -translate-y-2 -translate-x-2 scale-110 shadow-2xl shadow-blue-400 text-white
}
</style>
Now, if you set the mybutton class on the button, the hover will also work.
You can also add these classes to the main css file of your project. This is not the preferred way of tailwind, though. See Tailwind documentation.
For people using react who stumble upon the question, there is a better approach for the following:
const pseudoJoin = (selector, str) => {
return selector+":"+str.split(" ").join(" "+selector+":")
}
Now you can call it anywhere like:
<div className=`${pseudoJoin('hover','classes you want on hover')} some more classes`>Hello World!</div>
Or when you are using classnames framework:
<div className={ classnames(
pseudoJoin('hover', 'classes you want on hover'),
"Other classes here"
)}>Hello World!</div>
I am using sveltekit, typscript, and tailwind for this. Ok, I have a website that I am making and I have buttons that have no background and are formated like this:
When opened
- Label
stuff
when closed
+ Label
It worked and all but when I added a new div to be right next to those buttons the buttons stopped working completely. It would not even show the pointer hand.
Code for buttons:
<script lang="ts">
let expanded: boolean = true;
export let item: string = '';
export let value: string[] = [];
import Page from '../Components/page.svelte';
let pagen: string = 'About';
</script>
<Page bind:page={pagen} run="" />
<div class="dropdown flex flex-col mt-5">
<button
class="dropdown-toggle"
on:click={() => {
expanded = !expanded;
}}
>
<span class="dropdown-label text-gray-400 ml-5 flex text-lg"
>{expanded ? `- ${item}` : `+ ${item}`}</span
>
</button>
<div class="dropdown-content flex" style:display={expanded ? 'block' : 'none'}>
{#each value as val}
<div class="dropdown-item text-gray-400 ml-10">
<p class="inline-block text-gray-400">#</p>
<button
on:click={() => {
pagen = `{val}`;
}}>{val}</button
>
</div>
{/each}
</div>
</div>
The pagen that is binded is for the div that goes right next to it. (this is not important I think...)
Code for the page:
<script lang="ts">
export let page: string = 'About';
export let run: string = '';
</script>
{#if run == 'true'}
<div class="w-screen h-screen -z-10">
<div class="page ml-80 bg-gray-800 h-screen">
{#if page == 'About'}
<div class="flex flex-col items-center justify-center">
<h1 class="text-gray-400 text-3xl font-bold tracking-wider mt-
10">Some Title</h1>
<p class="text-gray-400 text-2xl font-bold tracking-wider">Some
Label</p>
</div>
{/if}
</div>
</div>
{/if}
These are both components in svelte and are imported in index.svelte. Buttons on top and page on bottom.
Helpful Images:
The website is being styled to look like discord.
Any help is greatly appreciated!
There are a few things I'm noticing that may help you get this working:
Nothing may be showing because values may be empty. When I added values = [ "a", "b", "c" ] I saw them no problem (see repl).
You're not setting run, so Page will never render. Also, using run as a string is weird since it appears it is a boolean?
If you're using Tailwind, instead use conditional classes:
<div class="dropdown-content flex" style:display={expanded ? 'block' : 'none'}>
<!-- should be: -->
<div class="dropdown-content flex" style:block={expanded} style:hidden={!expanded}>
Stylistic recommendation:
<span class="dropdown-label text-gray-400 ml-5 flex text-lg">
{expanded ? `- ${item}` : `+ ${item}`}
</span>
<!-- simpler: -->
<span class="dropdown-label text-gray-400 ml-5 flex text-lg">
{expanded ? "-" : "+"} {item}
</span>
Here is a repl with what I believe is working code.
I am using vue3 with vitejs in one of my projects and I have stumbled upon an issue. I have the following codes.
<div>
<p class="line-clamp-4">Some really long text here...</p>
<a id="read-more" href="readmore.html">Read more</a>
</div>
I am using tailwindcss here and I was able to clamp 4 lines. I have a list of these texts and not every one of them will have line clamp. So, I only want to show the read more button, when the line-clamp is applied. Now, how do I know the line-clamp is applying to this text and I have to show the readmore button?
Here is what I did to achieve this:
#foreach($module->captions as $caption)
<div class="mt-1 relative">
<div id="body-{{$caption->id}}" class="text-md leading-7 text-gray-700 font-normal whitespace-pre-line line-clamp-6">
{{ $caption->body }}
</div>
</div>
<div id="readMore-{{$caption->id}}" class="hidden flex justify-center absolute bottom-0 left-0 bg-white w-full rounded-b-lg">
<p class="text-blue-600 cursor-pointer py-2"></p>
</div>
#endforeach
<script>
let elements = document.getElementsByClassName('line-clamp-6')
Array.from(elements).forEach((element) => {
let captionId = element.id.split('-')[1];
let body = document.getElementById('body-' + captionId)
let readMore = document.getElementById('readMore-' + captionId)
if (element.clientHeight === 168) {
readMore.firstElementChild.innerText = 'Read More'
readMore.classList.remove('hidden')
readMore.addEventListener('click', (el) => {
if (body.classList.contains('line-clamp-6')) {
body.classList.remove('line-clamp-6')
readMore.firstElementChild.innerText = 'Read Less'
} else {
body.classList.add('line-clamp-6')
readMore.firstElementChild.innerText = 'Read More'
}
})
}
})
</script>
In my case I'm using a foreach to loop through some data but you should still be able to customize this to your needs. Basically, I'm getting all the elements that have a class name of line-clamp-6. Then were looping through those elements to see if they have a clientHeight of 168. If so, they need the Read More link.
Keep in mind you might need to check for a different clientHeight.
Then I listen for a click on the read more link if line-clamp-6 is present then we remove it else we add it.
Hopefully this helps you. I through this together in the last hour so there may be a better way to do it but this seems to work for me.
I am running a for loop with Alpine.js. I am using the Nunjucks template engine.
I have an array with three items called items
Is it possible to inject the item variable in the src attribute of the img tag? See code below.
<div x-data="{items: ['first-image.png','second-image.png','third-image.png'], active: 0}">
<div class="snap overflow-auto relative flex-no-wrap flex transition-all" x-ref="slider"
x-on:scroll.debounce="active = Math.round($event.target.scrollLeft / ($event.target.scrollWidth / items.length))">
<template x-for="(item,index) in items" :key="index">
<div class="w-full flex-shrink-0 flex items-center justify-center">
<img src="`../assets/images/favicon/${item}`" alt="" style="height:550px">
</div>
</template>
</div>
Definitely possible, what you're looking for is the x-bind directive.
You can "bind" a value from your Alpine.js component state to the src attribute using x-bind:src="someValue" or :src="" in shorthand
So you can do:
<img x-bind:src="`../assets/images/favicon/${item}`" alt="" style="height:550px">
Working in an Angular4 application ,In this I need to have a UI which contains the Grid view and List View options for displaying products .
I have designed the UI but I need to do some magics in Typescript,So I looking for SO.
I have referred some other examples nothing is worked for me .
Please refer my Stackblitz File : https://stackblitz.com/edit/angular-s8oogm?file=app%2Fapp.component.html
Where I have the HTMl,CSS and I want to enable the functions for switch between List and Grid View.
When I switch to list view I need to show the product like the below image ,For that my stackblitz file I have done the CSS but I don't know it's right or wrong .
Grid View
List View
Thanks.
you can create 2 nested components AppGridProduct and AppListProduct and call show them based on your display mode and send data to each component using Input:
<div class="btn-group pull-right">
<button class="btn btn-white" type="button"(click)="onDisplayModeChange(1)"
[ngClass]="{'btn-primary active': displayMode === 1}" >
<i class="fa fa-th"></i>
</button>
<button class="btn btn-white" type="button" (click)="onDisplayModeChange(2)"
[ngClass]="{'btn-primary active': displayMode === 2}" >
<i class="fa fa-list"></i>
</button>
</div>
<!-- grid -->
<div class="row" *ngIf="displayMode === 1">
<app-grid-container *ngFor='let product of productsList' [product]="product"></app-grid-container>
</div>
<!-- List -->
<div class="row" *ngIf="displayMode === 2">
<app-list-container *ngFor='let product of productsList' [product]="product></app-list-container>
</div>
and in your component.ts
onDisplayModeChange(mode: number): void {
this.displayMode = mode;
}
add this to your css:
button.active {
color: green;
}
add this insted of class='card' [ngClass]="isCard?'card':'list'"
and in your controller switch isCard flag based on the user input
You need to implement card and list classes and their child classes based on the ui requirements, also you can use isCard flag to show hide elements specific for grid and list view.