Vuetify - Overriding template slots with scoped CSS - vue.js

I got some problems with overriding the CSS on slots inside an autocomplete.
I read this thread and tried multiple solutions, but none work that are feasible (since they globally change the style for vuetify components):
How to override vuetify styles?
How would I override the autocomplete styles? E.g right now my problem is that I'm adding an append-slot with a button inside the search field, but the padding of the text field pushes it too much to the left & no padding is applied on the bottom.
Some things I tried:
Creating a parent element with an ID and then manually trying to create a class for it.
Example:
#handlesearch > div > div > div.v-input__slot > div.v-select__slot > div {
margin-top: 4px !important;
}
<template id="handlesearch" slot="append">
<v-btn
>Sök</v-btn
>
</template>

If you inspect your html, you'll notice that adding ID on <template> is not working. If you move your id="handlesearch" to actual html element inside your slot, which is in this case v-btn.
<template slot="append">
<v-btn id="handlesearch">Sök</v-btn>
</template>
with next scoped style
<style scoped>
#handlesearch {
background: red;
}
</style>
Produces next result:
If I move id="handlesearch" to <template> as <template id="handlesearch"> style will not be applied since in my DOM there is no HTML element with that id.
Solution
Move your ID to actual element inside your slot, and add scoped style according to that.

Related

How do I add a class to a slotted element?

In my my-dropdown component in Stencil, I have this:
<slot name="filter" />
In my HTML, I have this:
<my-dropdown label="dropdown" size="m" filter="true">
<select slot="filter" class="inf__dropdown-select">
<option>One</option>
<option>Two</option>
<option>Three</option>
</select>
</my-dropdown>
The class inf__dropdown-select is defined in the stylesheet of the component, and it used to be applied to the select element inside the component.tsx, but since I need to slot it now, I replaced the select element with a single <slot name="filter" /> slot, but now I don't know how do I apply the class? If I add the class to the slot inside the component, it's not being
applied. I thought adding it to the element that you are slotting would work, but it doesn't. How do I make sure the class is applied to the slotted select element?
You have implemented the inf__dropdown-select style class inside shadow DOM (the style for my-dropdown), but the class is being set on the select element which is in light DOM, so the style can never be applied to the element.
To style elements inside a slot of a web component from inside the component, you use the ::slotted() pseudo-element selector inside the component's stylesheet.
For example - the stylesheet for my-dropdown:
:host {
::slotted(select) {
...
}
...
}
You can also use other selectors inside the ::slotted() function such as ::slotted(.inf__dropdown-select), ::slotted(select.inf__dropdown-select) or ::slotted([slot="filter"]) depending on how specific you need to be according to the design of your component.
Important to note: Slotted content is reflected, NOT moved!
<slot> content is styled by CSS in the container
in the SO snippet below global CSS myClass
Below <style> can be inside the component (in lightDOM !!) or outside the component.
and inside the component,
the "skin" (only the first! element select) can be styled with ::slotted
For really deep dive, see: ::slotted CSS selector for nested children in shadowDOM slot
customElements.define("my-dropdown",class extends HTMLElement{
constructor(){
super()
.attachShadow({mode:"open"})
.innerHTML = `
<style>
::slotted(select) {
margin:3em;
}
div {
background:pink;
}
</style>
<div>
<slot name="filter">NO slot named: filter</slot>
</div>
`
}
})
<style>
select {
font:20px arial;
}
</style>
<my-dropdown label="dropdown" size="m" filter="true">
<style>
.myClass {
border: 5px dashed green;
}
</style>
<select slot="filter" class="myClass">
<option>One</option>
<option>Two</option>
<option>Three</option>
</select>
</my-dropdown>

Carousel via Vue (how use transition?)

I beginner for Vue, and I trying make carousel via Vue.
I have the code: https://jsfiddle.net/z3m76w5r/4/ (example)
<style>
.switch-enter-active,
.switch-leave-active {
transition: all .5s ease-in-out;
}
.switch-enter {
left: 100%;
}
.switch-leave,
.switch-leave-to {
left: -100%;
}
</style>
<div id="banner">
<transition name="switch">
<banner class="content" v-bind:slide="currentSlide"></banner>
</transition>
<div>
I want animated my carousel. But my transition-vue don't work, despite I looked at the docs and manuals.
Reason why your transition using Vue build-in <transition> component doesn't work is because its designed to work when some element/component is entering or leaving the DOM in context of:
Conditional rendering (using v-if)
Conditional display (using v-show)
Dynamic components
Component root nodes
Your image element is not entering or leaving DOM. Its just there and you are changing it's attributes (like url etc. - which cannot be animated in any way).
For your transition to work you need at least 2 img tags to exist in the DOM during the transition - one that is leaving the DOM and one that is entering the DOM. Easiest way to do this is by using v-for with key and transition-group instead of just transition. You just change the index of image, v-for will create new img element, apply "enter" transition to it and "leave" transition to old img element (for previous index)
You can find great example of that here

How to use a button inside v-text-field label slot

I need to insert a clickable button inside v-text-field under label slot. Meaning that there will be label : " Start typing or Select Search Panel" where "Select Search Panel" will be a link or button.
I'm able to make it visible using the v-slot:label but the button is not clickable and onSearchPanelClicked in not triggered..
<v-text-field class="input-field" clearable prepend-inner-icon="search" solo >
<template v-slot:label class="linkLabel" v-on:click="onSearchPanelClicked">
Start typing or <v-btn v-on:click="onSearchPanelClicked" class="link" flat > Select Search Panel</v-btn>
</template>
</v-text-field>
Is there any way to transfer click event to the element ? If I start typing the label must disappear like it used to work on v-text-field.
Regards
Jan
You have to overwrite your input .v-label CSS rule pointer-events.
Vuetify sets the label inside a v-text-field like this:
.v-text-field .v-label {
pointer-events: none; // unclickable element
}
So changing it to auto will enable your button inside v-text-field label to become the target of pointer events, just be aware of deep selectors when working with scoped styles at your component.
.v-input.input-field .v-label {
pointer-events: auto;
}
/* or for scoped styles */
::v-deep .v-input.input-field .v-label {
pointer-events: auto;
}
In this example the rule is applied only to fields with your custom class .input-field, if you'd like to overwrite for all the v-text-fields just remove it from the CSS code.

Vue: What is the cleanest way to select a component via CSS?

I have a bar component. It is used like this:
<template>
<div>
<!-- stuff -->
<bar></bar>
<!-- stuff -->
<!-- stuff -->
<!-- stuff -->
<bar></bar>
<!-- stuff -->
<bar></bar>
<!-- stuff -->
</div>
</template>
<style lang="scss" scoped>
#media (max-width: 1300px) {
// this selector doesn't work, but it would be nice if it did
bar {
display: none;
}
}
</style>
I would like to hide the bar elements when the screen is 1300px or narrower. It would be nice if there was a bar element selector, just like there are p and h1 element selectors. However, there doesn't seem to be, and I have to add class="bar" in order to select them.
My question is if there is a cleaner way to select the bar elements.
It wouldn't be good to add the CSS code inside of the bar component because when the bars are used inside of other components, I don't want to hide them at all.
A class seems to be the best way to go. Put it on the root element of the component if you want it to be universal for the component, or only on the component tag if you want it to be specific to that use.
Also, there is no reason you couldn't use a custom tag as the root element of your component; as long as the tag didn't map to a component, it would be left in the DOM, and you could use it for CSS selection. I don't recommend it, though, as I don't think this use case is a good reason for introducing a new tag.
If your component template looked like this, for example:
<template>
<bar-container>
Hi there
</bar-container>
</template>
and you had no bar-container component defined, you would be able to use CSS to select bar-container, which would be the container element for every bar component. But it's just as easy to use <div class="bar-container"> instead.
After better understanding the problem at hand, would this work?
<div class="someClass">
<bar v-bind:width="draw.probability" type="draw" ref="myComponent"></bar>
</div>

Nested Custom Elements in Aurelia not rendering as expected

I have a custom element that defines a general purpose UI widget frame with various bindable default options, a template part for adding some additional 'toolbar' options and general-purpose <content /> for the body.
I then have another custom element for some administrative functionality. The latter element should present itself as a widget, and it too has various template parts.
However, if I try to embed the former widget element into the latter administrative element none of the content gets rendered.
Here's a simplified example:
eg-block (Widget) element
<template>
<div style="padding: 10px; background-color: #bbffff">
<content></content>
</div>
</template>
eg-list (Admin) element
<template>
<require from="./eg-block"></require>
<eg-block>
<div>Start of List</div>
<content></content>
<template replaceable part="list-part">Default List Part</template>
<div>End of List</div>
</eg-block>
</template>
Containing Page
<template>
<require from="./eg-list"></require>
<eg-list>
<template replace-part="list-part">Replaced List Part content</template>
<div>Replaced regular content</div>
</eg-list>
</template>
I was hoping the results of that to be:
<div style="padding: 10px; background-color: #bbffff">
<div>Start of List</div>
<div>Replaced regular content</div>
<div>Replaced List Part content</div>
<div>End of List</div>
</div>
But instead it gives me:
<div style="padding: 10px; background-color: #bbffff">
<div>Start of List</div>
<div>End of List</div>
<div>Default List Part</div>
</div>
So it doesn't render the list's content or replaced template part that is specified in the containing page. But additionally, the default content of the list's template part is actually rendered after the list.
Is this the expected behaviour? And if so, is there any way to retain the use of the widget/block element within the admin/list element but to have it render the way I was hoping?
I'm mostly copy/pasting my answer from this question here, but here goes:
Let me preface this answer by saying that content projection is changing completely (and for the better) in Aurelia RC1. We are moving to slot based content projection to match up with the newest version of the shadow DOM specs. This spec is much more powerful than the selector based setup that Aurelia has current (which is based on an earlier version of the Shadow DOM spec). This is the only breaking change we have planned between now and the full 1.0 of Aurelia.
So everything I'm telling you will be obsolete very soon.
In the meantime, the element in your custom element view needs to be at the root of the template. As to the why Aurelia is acting this way, well it's a bug:-) It has been fixed in the new implementation.
We just released a blog post regarding the new slot implementation, if you'd like to see how things will work.