Using Web Components with VanJS and Shoelace
Tags: vanjs
Published: 2023-05-30 20:19:19

It's very straightforward to use web components with VanJS.
Here we use the excellent web component library [Shoelace](https://shoelace.style/)

[Demo](https://flems.io/#0=N4IgtglgJlA2CmIBcAWFA6A7AZgDQgGcBjAJwHtZZkBtABlwEZsAmAXXwDMIECbQA7AIZhESEOgAWAFzBV8RMvynwlyEAB1+AHlgR+AawAEJeLAC86wlICePCfHhTLhiSY4WQ0qQAcCSAPT+RFD86ABWBFCmEABuJOj8jv783mD+AAIEEmSmgkTwALQENgj+WTmwefDpzOgYtP5QEMX+UvYiBP66AObS6EQEBM7+AHyaWsQkEN5Shjbe8B5gZFAArgjOBCREHl6+AUEh4ZHRcQlJKWmZ2bn5RSXwZTeV+TV16A1NLeW3hYKrUgoZEEUXiEUsIy0ZVI0ykY344wkDEMxVsi0sygAHlICoIevwkPklPASBDNIZDAA1QT8ABSAGVDDSoIZ6c8quN-Ej4VomjFDNAPIJvN4ydpGrF4ZoQPgCKZ4EQpBBFLwxCgkNhaCAAL64ATCUQgGI044ykAKYmqMQIWbwXBSXD8XDmADyACMwgqHSQzO7PYr0N1HAAFciA+bwF0cXAEMwACjtDqdsAAlGYRgmAPyZuNyqQAFQgIjIALjyZTjvgAHdWY4Uyn0CCoHGpBWoGZgEHZsbYHGU8ATFJViR+HMJM10FJdXnDD2E-2bYZ+GY2s1nWZQlIANzwACEZjMsAAZEey+hzAfYJmpGYCC3HbgiCmkIsD6Fj0epOgojb4GWK5uZh2qEZDoBwZAkAAonkEhxi26ZSAmzr1vWuqKIkVbzsAq4EOgoHeKsWTztqaFmCQcZQBWEBAem8AJCs8D5tYCyZvASAYYY+bwNi864Ks8Z2ugQmtumLZgZUiEMP4tANuBUEwXBN4jHRwoLPwUAAMLjrAzbkSJB5QJmmEOgmtH1kgEAtihFbwBWggbtWhihmQmLWHB95CQkaYjMANrUAQuCeRArBkWWdCsNmMkHmYZCZgS1DALqnn8Ow9lQGQRCrCISj9CYgjKJBCDZYhrZboOw6jrA6AqFIUzwHeBCyRB0FELBcHUEmrDeb5jiGOYggdaw+5Aax6YDVIIVsYsIyCOgeYAIJSLVEBugCf4OrZZX-tFhmYU6pkZr2tm4IIKFIOR-BpgesWYcl37wL4uBwZ5tmib2oQcHGL31idZ3vSm2o-ascaCIFQkQADFado4SD3pdCHoG6ejNsBkO4AA+jRynoNRdEQGB3DKORB10asmY4wQGnoV68CURWOx9umPWzMu1CeRNW43sBjn0o4Z4cBJACywpxuj9Zgc1CnwT5NrAOj7F8UgsC4N053aiuMahXdYAiyTk4-cr2u69NdGpvWW4EMNH65vu8CZlVJjeC88AAOoQG0Yn8ZZjXPnGDvwMsMR-hWX78bZkMARL8mtXBJvnkB+sA7gVbxuz3WLuYX4ELo+RxvQBQMBWPpSB154qN0bQF+w7bkZ5VU694se0YnKZbhAn3tkBKblSO1CsFui5kB28vK6sFkURWqskNqZWOBVfVRy1bVKcAy53k6JmMxmH2SzHYuOl3FYMPA2Ahzj6AEURZAR7goGrDP3HeBBsxRBw-ywFIwBNkgqz2oI3R+FBsUfKU1RJy3Rt4MMZB0byygPaF8zoEEQCQH3W+KDWCA1wEjdSSAqwzzNHKBAiplT8FVCAWgSAGAMAAJzUJ1HqEAQgRBqFNPIRQygrQgCLE-Eg3YaSGA4OQMAhhLDoH8MaUI4INAIn4BaYohhgCaHUFIPkuAlFtGYGohEUg3QkC0coos3R9FSGKOQfgRj1EEB1pQYxrhjGWGzgUEg+U9DdEsEgVksAABKLjzH2MILAAoq0lqKHcZ4gAQgCQETp1EOMCUQQQJAoBhPpLADSiS4HkhEQEgoegCJOGQJ4gAkikAEmhtSGDMLOE0Uh-5DBkXI2YtSSBdkqYYdKmViqBkcIVAONVwnWCKc2SwqlLCtyUfwDgqxZFKkUIYAA4uQVY3hIkhNIX2RRMjlGNOqVMGkswqkSLmrU5QcZRFCTGVuCZ2yVSzAkMyBAGkc5GCqfASpIxdkQH2egHsbSEyTkSV2bpUhFrLWCX+Swxo9lKDGeMrZUgdkxAgI5KpfIznaOURIZgZyQCrOiQQQwHjLC4E+fsissSVGxHRcomlUhUl4sUHGTZtLaVQq+UoIlIBX7vwKRS5RupsmKHgGM+xTg6WwAZfwJlfKxVsv2ZyyBRZEnWEsDKgVGIqxkBFTK+lUTGXMrFayxJ7KpCcqgDSIMpJpEsqnCSjErgHBjIpeS7RKZ1FIurHhWRzy2n3PUo855VztE91HB6qsQbtQTKmTMkhhh0lJI2eokNnj43NgNbSoglRBicoSUkgoZAg4kDDaqjFtrrlisMdK0tyjs5kFNdkpVQZiUyq2EQTlew-CBEbfVdA0yCBO0EFkfoZA0jeGyICAuABWSd1DmC0GoQwTAzACi0A4BwAAHBwAAbFAFA1C12YEzBATEug3RkTdAXdAtQGBHmPYKeA1haQSCIAACXCW-F2ABFCALowiQWsILAAIlAahR5-iAjMHJHWUgjxcBvKQMg3gjwp0nbQWgR4ACOZh120GbdW2pH9OXzUMPod2HCUTuwJd4FxNVYDWEMG6RwVYHCjkEHMEkziFBLTY0-WYzJ2kKggi4oOhhujOMGD2kttLMEUtMYoboOLBZkZUCKhj5EXUspAPmccBLSNLRUAKAlg7DCZWUEyAl9hDOGAHdYKZVVDDhKmOYlwRYXAjreYCc11hdzErU32UVVi8S9ksFuwwzH4D6AJRQZJIANOlrRemw1JjYB1s5eBOtJIpNJd1DqiVeqpWJaNdC+tlhFU6xICqmUMrlHeG4LATlWXpN2pAILCCbySngQpNkjTSXUk+KVOYvszr1Fuv4JGmR0biFzJKfkxNo4TO3OqbAVYbzDkmmAacyweSATsexJ5J182dnpWEVU9pVKskUjRT2FbLqut+du111JM3SzAAHfkbIOkSRIEsJBYkJBdsFMBlk0bFIdnbYOe0kd6AMMrYq7zIhgJyJxNyaUgpIOBSo69eDv5KZ3lLZWz8vEbTweE+W8K+bybjvlImUcps6KKTNK7Ha7RiySwrPy3eclOj1O2OxZYVN2rtGpv82pww-mslYpxc9tHWiKTS5F7oobl0CHyim6QtQFDaAFHXZgSh9D9TMLEP0QYZoLQcKkGoN0Kx6ObIZ9xHEeIIDdAJESImQaKRVmgG0VAaHvCYnd4Ycr3Q9BIFoEyAEZAA8KBSyQDxboXj6AD26PI+gxMlhwWF8cygI0TP6Bk-Nhaw0KIu4HwQmICie6gN7wwmpaB+4D+NrJee80FpJEXwLlBi-zdB0CWPuy4wFCKPE3vBREgAmcYE1DMkG8TIpM3qABe2-IprP5FLN4ADk6Wibr9YF3u7XwbMeIFtxAPFIwiESVBwawBQzc1Q8f2qoQSmMsdP0yfEuTlBgD8CZmqJIZ-zelFlFV1mXVzVEoUnR1HYEYQNDUGpDpHpDZAqCqB1CAA)

```js
import van from "./van.js"

const {
	div,
	h2,
	br,
	img,
	strong,
	small,
	hr,
	"sl-rating": SlRating,
	"sl-button": SlButton,
	"sl-card": SlCard,
  "sl-input": SlInput
} = van.tags

const target = document.getElementById("app");

function GroupButtons(){

	const variant = van.state("...");

	const handleClick = e => variant.val = (e.target.getAttribute("variant"));

	const view = div(
		h2("Buttons : ", variant),
		div(
			SlButton({
				variant: "default"
			}, "one"),
			SlButton({
				variant: "primary"
			}, "two"),
			SlButton({
				variant: "danger"
			}, "three")
		),
	)
	view.onclick = handleClick;
	return view;
}

function Card(){
	return SlCard({
			class: "card-overview"
		},

		img({
			slot: "image",
			src: "https://images.unsplash.com/photo-1559209172-0ff8f6d49ff7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=80",
			alt: "A kitten sits patiently between a terracotta pot and decorative grasses."
		}),
		strong("Mitten"), br(),
		"This kitten is as cute as he is playful. Bring him home today!", br(),
		small("6 weeks old"),

		div({
				slot: "footer"
			},
			SlButton({
				variant: "primary",
				pill: ""
			}, "More Info   "),
			SlRating()
		)
	)
}

function Input(){
  const value = van.state("input text...")
  const dom =  div(
    div(value),
    br(),
    SlInput({placeholder:"Enter text"})
  )
  const input = dom.querySelector("sl-input")
  input.oninput = () => value.val = input.value
  return dom
}

van.add(
  target, 
  GroupButtons(), br(),
  h2("Card"),
  Card(), br(),
  h2("Input"),
  Input(), br()
)

```