While working on my NFO editor for Kodi I ran into an issue when dealing with fanart
since Kodi supports multiple fanart and my simple JavaScript function had no way to broadcast an event back to the main script. I had played with Web Components a bit in the past but was usually frustrated by the code. While there are plenty of great resources out there they rarely broke down clearly what I wanted to accomplish so I thought not only was this a great opportunity to learn something new but also pass along some things that might be helpful for others getting into the game.
I'm organizing this the similarly to how the MDN examples at web-components-examples are set up but with each component .js
file named the way the element is used. There is a sample html
file to show off the functionality but I definitely need to work on better documentation.
None of these components currently work with form submission as I use them with fetch
APIs. At some point I will modify them to follow the formAssociated
guidelines as seen in More capable form controls.
There are many image upload with preview solutions out there, this one is mine. It supports file selection and drag/drop, images and video, add and remove events as well as a simplistic zoom. I hope to make the zoom more full-featured and add crop functionality in the future. The sample page demonstrates adding/removing new instances of the element and a 'Save' button will console.log()
the current media.
<media-upload types="image/jpeg image/png image/webp" value="sample.png" addable removable>
All attributes are optional.
types
are theMIME
types the element should accept separated by spaces. If none are provided all possible types are set which areimage/jpeg
,image/png
,image/webp
,video/mp4
andvideo/webm
. Currently unacceptable types only produce aconsole.error()
message.value
is an existing media reference to show when the element first appears. When saving you can.getAttribute('value')
orelement.value
to get the current media. Fireschange
event when the value changes, current value can be retrieved fromevent.target.value
.addable
indicates the user has the ability to add another instance of the element. You can use.addEventListener('add', function)
to handle the event.removable
indicates the user has the ability to remove that instance of the element. You can use.addEventListener('remove', remove)
to handle the event.
When focused Spacebar
will act the same as a click
event, opening the OS dialog to choose a file. Z
or zwill zoom the current media.
Escapewill clear the current media or close zoom.
+and
-will trigger the
addor
remove` events if those attributes are enabled.
The element has a number of internal styles that I probably need to work on since my pages are based on a full reset. In your own CSS
you will need to specify dimensions for the element so all the internal elements can scale to that size.
Another common pattern, this one was very frustrating owing to how document.createElement
and svg
don't play well together. No half-stars here, I'd have to find a different way to render the stars and probably lose the fancy schmancy rounded corners (unless som CSS
genius wishes to step forward 😀), but Kodi only uses one to five for it's userrating
. But I'm happy with the live highlight of stars as you hover over the component. Clicking on the current number of stars is how you remove the value.
<star-rating stars="10" value="3"></star-rating>
All attributes are optional.
stars
is the number of stars to display. The default value is5
and the minimum is1
. There is no limit set but, y'know...value
is the number of stars set. Rather than supporting0
stars excluding this attribute, or selecting the current number of stars, is meant to indicate no value set. Fireschange
event when the value changes, current value can be retrieved fromevent.target.value
.
When focused ArrowLeft
will decrease value
until null
. ArrowRight
will increase value
until the value of stars
then will set as null
allowing the user to wrap around and continue pressing the key indefinitely.
This is an opinionated display in terms of colors, yellow for the current number of stars, gold when hovering. Otherwise it will scale with font-size
as my use-case is inline but there's no reason you can't put it into a block-level container.
An approximation of the iOS toggle as a replacement for the standard <input type="checkbox">
form control.
<toggle-switch checked disabled></toggle-switch>
All attributes are optional.
checked
indicates the componet is currently in theon
state. Using.getAttribute('checked')
orelement.checked
will return aboolean
indicating whether the switch ison
oroff
. Fireschange
event when the checked attribute changes, current value can be retrieved fromevent.target.checked
.disabled
indicates whether the control can be toggled by the user.
.toggle()
can be used to simulate user interactivity with the component. Callingelement.toggle()
is the same as sending aclick
event which will be ignored if the component currently has thedisabled
attribute set. Usingelement.setAttribute(state)
is the only way to change the state regardless ofdisabled
.
When focused both Enter
and Spacebar
with toggle a non-disabled
instance.
Another opinionated display in terms of colors, using greys for the off
state background and off-green for on
. Opacity is used to indicate disabled
. The component will resize height based on font-size
of the containing element.
A fancy (for me 😜) progress bar as a replacement for the standard <progress>
element. It uses the same attributes so it can be a drop-in replacement.
<progress-bar value="0" max="100" gradient="linear-gradient(43deg, #4158D0 0%, #C850C0 46%, #FFCC70 100%)" nostripes></progress-bar>
value
is the current progress of the control. It defaults to 0 and if it exceedsmax
it is set tomax
.max
is the maximum progress. It defaults to 100.gradient
allows a custom CSSbackground-image
for the progress bar. This should be in the standard CSS format.nostripes
will disable the animated stripes normally applied to the progress bar.
Mostly opinionated in terms of the border radius. There is a default gradient which is green-ish. The primary element is filled with an inherited background-color
. The element scales based on font-size
.