I'm using the Algolia search widget (VueJS) from Algolia, and everything works fine, but on focus the search input field displays an unwanted inner border (outline) that I cannot remove so far.
I cannot directly define 'outline:none;' on the ais-search-box element, because that has no effect (it's being replaced in the DOM I think is the reason).
How can I get rid of this inner border/outline?
My code is:
<ais-search-box class="shadow appearance-none border rounded px-3 text-gray-700 mb-2 leading-tight focus:outline-none focus:shadow-outline" placeholder="Search" autofocus>
<div slot="submit-icon">
<i class="fas fa-search text-xl p-2 text-blue-400"></i>
</div>
</ais-search-box>
I have some similar issues, when i work with PrimeVue in my Vue.js project. Most of the components are replaced in the DOM during render. My approach is to identify the type or class of this element after it is rendered. Then I give it´s parent a class and construct my CSS non scoped in my main vue-file.
If you give your parent the class shadow, your css could look like this:
.shadow input[type="text"]:focus {
outline: none;
}
Related
I am using tailwind (flowbite) css for web components that comes with respective css and js.
I want to implement acordion component (https://flowbite.com/docs/components/accordion/) and fill its data dynamically using Vue.
<li
v-for="({ username, email, role }, index) in myUsers"
:key="username"
>
<h2 v-bind:id="`accordion-open-heading-${{ index }}`">
<button
type="button"
class="flex items-center justify-between w-full p-2 font-medium text-left text-gray-500 border border-gray-200 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-800 dark:border-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800"
v-bind:data-accordion-target="`#accordion-open-body-${index}`"
aria-expanded="true"
v-bind:aria-controls="`accordion-open-body-${index}`"
>
Seems that the vue part works fine, it grabs the data, creates respective HTML li - lists and changes its HTML tags for accordion access (accordion-open-body-1, accordion-open-heading-1 ..)
However, JS that cmes with flowbite can not grab that changes and throws the following error:
Please, advice how can I fix this issue.
Change
<h2 v-bind:id="`accordion-open-heading-${{ index }}`">
to
<h2 v-bind:id="`accordion-open-heading-${ index }`">
👆 👆
I have a global confirmModal.vue which looks like this:
<template>
<Transition
appear
enter-from-class="opacity-0"
enter-to-class="opacity-100"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
>
<div
#click="$emit('cancel')"
class="bg-black/50 z-50 fixed inset-0 flex justify-center items-center transition duration-300 ease-in-out p-8 cursor-pointer"
>
<Transition appear enter-from-class="scale-50" enter-to-class="scale-100">
<div
#click.stop
class="flex flex-col gap-4 shadow-2xl p-8 rounded min-w-[300px] max-w-[480px] bg-lf-white transition duration-300 ease-in-out cursor-auto"
>
<h3 class="font-medium text-2xl">{{ title }}</h3>
<p>{{ text }}</p>
<div class="flex justify-end gap-2">
<Button #click="$emit('cancel')" variant="white">Annuler</Button>
<Button #click="$emit('confirm')">Supprimer</Button>
</div>
</div>
</Transition>
</div>
</Transition>
</template>
The first transition adds a fade in effect to the backdrop while the nested transition adds a smooth apparition effect for the modal itself.
It works fine but what I don't understand is that when I close the modal, the leave part of the transition does not trigger at all.
This is what the component calling this modal looks like:
<ConfirmModal
v-if="showConfirmModal"
title="Suppression"
text="Êtes-vous sûr de vouloir supprimer cet article ?"
#cancel="handleHideConfirmModal"
#confirm="handleConfirmAction"
/>
Here's a gif of what it's currently looks like:
EDIT: I achieved the wanted result by wrapping ConfirmModal.vue with Transition from the parent component, like this:
<Transition
enter-from-class="opacity-0"
enter-to-class="opacity-100"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
>
<ConfirmModal
v-if="showConfirmModal"
title="Suppression"
text="Êtes-vous sûr de vouloir supprimer cet article ?"
#cancel="handleHideConfirmModal"
/>
</Transition>
I don't understand why I have to do this and why in this exemple the person doesn't need to do that though, they use Transition from inside the child component and the transition works fine
It's also not ideal because every time I use this component I will have to think to wrap it inside this transition for it to fully work
It's probably caused by the use of different versions of Vue.
Your question is tagged vuejs3, so you are very likely using Vue 3, but, in the example you linked, vue version 2.6.4 is being used.
In vue 3, at least, you must use the directives v-if or v-show in the root element inside the Transition component for it to trigger the changes whenever the root component inside appears and disappears.
you can read more about transitions here
I have a parent component, SearchComponent:
<template>
<div>
<div class="relative pl-8 pr-10 rounded bg-white border focus-within:bg-white focus-within:ring-1">
<input v-focus #keyup.escape="clearSearch" #keyup="doSearch" v-model="searchTerm"
class="w-full ml-4 h-12 pl-1 text-gray-700 text-lg rounded-full border-0 bg-transparent focus:outline-none placeholder-gray-400"
placeholder="Search..." autocomplete="off">
</div>
<ul class="bg-white mt-4">
<quick-search-item v-for="item in searchResults" :key="item.id" :item-data="item.itemData">
</quick-search-item>
</ul>
</div>
</template>
This is responsible for receiving user input and getting results from an ajax call, handling errors etc. and generating the result list.
What I'd like to do is to make this generic so that instead of having a quick-search-item child component I can pass in different types of child component (like car-search-item, person-search-item etc.) depending on the context of where the user is in the app and what they're searching for
I've read a number of tutorials and I couldn't find quite what I'm trying to do. This may mean I'm approaching this in the wrong way - but if anyone could point me in the right direction, or has a better approach, I'd be very grateful.
Thanks,
Lenny.
I would try to make use of the <slot> element. Check out the documentation here
<parent-component>
<slot></slot>
</parent-component>
Hope this can put you on the right path.
Schalk Pretorius was quite right: slots are the answer to this, specifically scoped slots. I found the Vue docs a little confusing as it refers to getting data from the child component and I wanted to do it the other way around, so as an aide memoire for myself and to help anyone else here's what I did:
In my parent component I defined the slot like this:
<slot name="results" v-bind:items="searchResults">
</slot>
The v-bind binds searchResults (a data item in the parent component) to the value 'items'. 'items' then becomes available in the slot.
In my child component I have a simple property setup called items:
props: {
items: {type: Array},
},
Then to hook it all together in my Blade file I did this:
<search-component endpoint="{{ route('quick_search.index') }}">
<template v-slot:results="props">
<food-results :items="props.items">
</food-results>
</template>
</search-component>
This creates the search-component. Inside that -as I'm using named slots - we need a template and use v-slot to tell it which slot to use (results), then the ="props" exposes all the properties we've defined on that slot (in this case just one, 'items').
Inside the template we put our child component and then we can bind items to props.items which will be the searchResults in our parent component.
I'm happy to have this working and I can now create lots of different results components while reusing the search component - and at least I learnt something today!
Cheers,
Lenny.
I tried to add an #click to a font awesome icon. However, whether I add an #click event to span or i tag, it doesn't work at all. I suspect the event is taken by the input field. How can I make the magnifier icon clickable?
<div class="control has-icons-right">
<input v-model="keyword" #keyup.enter="findName" class="input is-large" type="text" placeholder="Input 1 word, hit Enter"/>
<!-- or 2 words separated by space -->
<span class="icon is-right" #click="findName">
<i class="fa fa-search"></i>
</span>
</div>
Source: 3sName.com
It is because, you are using bulma class .icon which having the following css.
pointer-events: none;
Try to override it with
pointer-events: all;
pointer-events css will prevent your element from emitting a click event.
:)
use a button / anchor 'a' instead span to wrap the fa-icon, along with #click method? Span isn't good practice for click event as well.
Have you tried #click.prevent="findName" modifier?
I'm trying to make a clickable "star" icon using font-awesome with bulma, switching between regular and solid styles (fas and far) in Vue, to achieve this I have the following component:
<template>
<span v-if="isStarred" class="icon starred config-icon clickable-text" #click="unstar">
<i class="far fa-star" title="Unstar Ranking"/>
</span>
<span v-else class="icon unstarred config-icon clickable-text" #click="star">
<i class="fas fa-star" title="Star Ranking"/>
</span>
</template>
The value isStarred is being updated properly and the span elements are updating accordingly. However the i element with the icon doesn't update until I fully reload the page.
I was able to make this work with v-show instead of v-if but I don't understand why this wouldn't work.
Vue tries to render elements as efficiently as possible, often re-using them instead of rendering from scratch. This isn’t always desirable though, so Vue offers a way for you to say, “These two elements are completely separate - don’t re-use them.” Add a key attribute with unique values:
<i class="far fa-star" title="Unstar Ranking" key="unstared"/>
...
<i class="fas fa-star" title="Star Ranking" key="stared"/>
Now those i elements will be rendered from scratch each time you toggle.
You can also update your classes with class binding:
<span v-if="isStarred" v-bind:class="{starred: isStarred, unstarred: !isStarred}" class="icon config-icon clickable-text" #click="toggleStar">
<i v-bind:class="{far: isStarred, fas: !isStarred}" class="fa-star" v-bind:title="title"/>
</span>
I switched the [fontawesome/js/all.js] to [fontawesome/css/all.css], and it solved the problem. I guess the fontawesome js is rendered after the vue.