
Shoelace 2.0 release: UI toolkit that works with all frameworks or none at all - 1337shadow
https://shoelace.style/
======
claviska
Shoelace author here.

A couple days ago, I released Shoelace 2.0, an open source library of common
UI components.

These components work with any framework, can be loaded via CDN, are fully
customizable with CSS (no preprocessor required), and install easily with a
simple script + stylesheet. They were built with Stencil.js, which is a
fantastic tool. The end result compiles down to vanilla web components.

Each component was designed from scratch to be lean, customizable, and easy to
use. Accessibility is a common question folks have about component libraries.
I’m definitely not an expert here, but I've spent a lot of time trying to get
it right. I would like to echo the experts and say that accessibility only
starts with components, but hopefully having a good foundation to build on
will encourage others to think about it more at higher levels.

I hope you'll take a second to check it out! I'm happy to answer any questions
you have about the project, how it's built, etc.

~~~
manjalyc
Longtime user of bootstrap & tailwindcss for pet projects. I've looked at the
'What Problem Does This Solve', but I'm not sure where Shoelace could fit into
my workflow.

Bootstrap is great for when I just want to quickly prototype and build a
decent looking interface, but it feels confined when I start wanting to style
things myself. When designing MPAs I typically use Bootstrap.

Tailwindcss is great for styling anything and everything, but I find sometimes
I waste too much time styling little things that other CSS frameworks already
have nice defaults for (and I am a terrible designer so this compounds my
dificulties). I often use tailwind for SPAs.

Forgive me if my question is a little naive, but where could I fit Shoelace in
for pet projects? Do you see it as being a suitable replacement for one of
these usecases? Complementing them? Does it lie somewhere in the middle?

~~~
claviska
Shoelace is more akin to Bootstrap. You can use it for quickly tinkering,
prototyping, or as a foundation for your own design system.

One thing Shoelace doesn't provide right now is a set of base styles. I've
considered offering these as an opt-in CSS class or a <sl-prose> component,
but I'm not sure it belongs tightly coupled with the library.

On one hand, it makes sense to provide a single "theme" that styles both
components AND the underlying website/app. On the other hand, this will make
themes very opinionated and potentially overbearing. I still need to think
about this more.

In the meantime, you can use something like Tailwind's typography plugin [1]
to handle base styles and use Shoelace in lieu of Bootstrap. IMO Shoelace +
Tailwind is a great combination for those who prefer utility classes.

1\.
[https://github.com/tailwindcss/typography](https://github.com/tailwindcss/typography)

~~~
Ataraxy
What would be the convention for using tailwind to style components in
general?

~~~
claviska
You can use Tailwind classes on all your markup as you normally would. In
terms of Shoelace components, they're more limited to layout, spacing,
flexbox, grid, etc. for arranging and positioning (e.g. don't expect
class="btn btn-blue" to turn a Shoelace button into a Tailwind button —
although you can use them alongside each other if you want).

To style the _internals_ of a Shoelace component, you can target it in a
stylesheet using CSS custom properties or CSS parts as described in the docs.
[1]

1\. [https://shoelace.style/getting-
started/customizing](https://shoelace.style/getting-started/customizing)

------
chrismorgan
My biggest concern with using Shadow DOM for things like this is that it makes
it depend upon JavaScript, which I strongly prefer not to do.¹ I know there’s
some research work into declarative Shadow DOM², which has the potential to
resolve this, but that’s still quite some way off. As it stands, I don’t feel
comfortable using Web Components with Shadow DOM for things like this, which
is a pity, because it’s a _delightful_ way to work, and this toolkit looks
very good in most regards. Instead, I like Svelte’s model which essentially
allows you to _write_ things this way, but have it result in light DOM, so
that you can still do server-side rendering if you desire.

¹ Requiring JavaScript harms accessibility, especially for web _pages_ (as
distinct from web _apps_ ). It makes pages take longer to load, not be as
spider-friendly, and be more fragile when JavaScript fails to load, whether
deliberately or accidentally—and simple network failures and the likes break
things more often than you might imagine. I myself browse the web with
JavaScript disabled via uMatrix, mostly because it speeds the web up a lot on
average. Privacy improvements are a distant secondary reason. When I encounter
pages that require JavaScript, I either give up on them or open them in a
Private Browsing window, where I don’t have the uMatrix extension enabled; or
if it’s something I expect I may be using more than once or twice, I see about
more precise whitelisting in uMatrix.

²
[https://github.com/whatwg/dom/issues/831](https://github.com/whatwg/dom/issues/831)

~~~
GordonS
> Instead, I like Svelte’s model which essentially allows you to write things
> this way, but have it result in light DOM, so that you can still do server-
> side rendering if you desire

I've never used web components before, and I use SSR a lot (ASP. NET Core) -
are you unable to use SSR with all web components, or only those that use
shadow DOM? What's the reason I can't just render an `<sl-whatever>` and
render the `value` attribute at the server?

Apologies if I've misunderstood or got some of this wrong!

~~~
chrismorgan
It’s just the Shadow DOM, because it doesn’t serialise (which is roughly
demonstrated thus: if you take document.documentElement.outerHTML it won’t
include any of the shadow roots, and there’s nothing you can do in a .html
file to produce a shadow root without adding JavaScript to insert it).

So if you have a component looking like this in your dev tools:

    
    
      <sl-emoticon which="smile">
        #shadow-root (open)
          :-)
      </sl-emoticon>
    

Its HTML serialisation will still be <sl-emoticon which="smile"></sl-
emoticon>, never with a :-).

Look, there _are_ ways around this lack of serialisation of shadow roots; the
examples in [https://github.com/skatejs/ssr](https://github.com/skatejs/ssr)
succinctly show early experiments in the field, where it serialises the shadow
root as an element, which it then turns into a shadow root with an inline
script—but if the JavaScript doesn’t run, that won’t work and you’ll be left
with a weirdly broken element, so I disqualify it and say “Shadow DOM is
incompatible with SSR”.

But for Web Components in general, there’s nothing stopping you serialising
them with their light DOM, though if your component goes adding children to
itself when or after you connect it you might need your connectedCallback to
detect if this has effectively already happened (on the server side), and wire
things up instead of changing its children. This process (wiring a JS-side
component tree to an already-existing DOM, rather than rendering from scratch)
is known as rehydration and applies to more than just Web Components.

~~~
GordonS
Hmm, this all sounds... complicated. Incompatibility with SSR is a deal-
breaker for me (I mainly work with ASP.NET Core), so unfortunately I don't
think this is for me afterall.

~~~
ergo14
You can do that, I render web components with python. Treat them as black-box
custom HTML tags in your server side template.

------
thrownaway954
Maybe I'm just a moron but when I see framework or libraries like this, I want
to see examples like bootstrap. I see nothing on the homepage that shows me
what this actually does. Again... Maybe I'm an idiot, but in today's age,
everyone wants things visualized. I think showing some examples right off the
bat could not only show the benefits of using this, but help explain it better
to people like myself. As of now I see no reason to use this.

~~~
claviska
This is a great idea. I ended up publishing the documentation site _as_ the
website and didn't even think to show some examples.

~~~
thrownaway954
DUDE!!!!! AWESOME!!!!! now that is what i'm talking about!

I am in love with the tooltip :)

[https://shoelace.style/components/tooltip](https://shoelace.style/components/tooltip)

------
kstenerud
I'm still shocked at the decades it took for web technology to "discover"
component based architectures. It's the main reason I steered clear of JS and
web tech as much as I could, with a small dalliance to Echo2 in 2007.

~~~
DaiPlusPlus
The problem with encapsulated components is you surrender flexibility. For
example, “components” for things like buttons and checkboxes are
straightforward enough. But what about a checkbox-list? And how does that
component accept data for data-binding purposes?

Another place where “components” generally fall-over is when a component needs
to act as a parent or container for arbitrary markup: yes, there’s the “slot”
system but those are still defined and controlled by the component, not the
consumer - even though ultimately it’s the consumer’s application.

I compare the situation to the component ecosystem for VB6 and WinForms -
which to be fair was a lot worse as consumers often had little to no control
over how those components rendered, appeared or behaved - but (no pun
intended) elements of the same problem exist today.

Another example is WPF - which has major unaddressed issues still - which to
be fair is worlds apart from WinForms in terms of what it’s templating system
is capable of. A nice thing about WPF was that a component (Control’s) XAML
was transparent and editable at design-time in VS, so the consuming
application’s developer could get what they want out of it, the catch was that
WPF templates are horrendously complex: getting VS to expose the XAML for even
a <Button> would dump 50KB+ of markup into your application XAML because it
was an all-or-nothing system and you needed XAML for every button state and
behaviour - right down to the pulsating button glow effect that was only ever
used in Windows Vista...

~~~
claviska
It's not always easy to provide a good dev exp with complex components, but
it's not impossible. Using composition wisely can offer endless flexibility
while maximizing code reuse.

For example, Shoelace's <sl-select> component mimics the browser's <select>
component. It has single select, multi-select, size variations, shape
variations, type-ahead selection, validation states, etc. This component is a
composition of <sl-dropdown>, <sl-input>, <sl-menu>, etc. and its entire
source is less than 500 LOC (including doc comments and prettier formatting).

This is significantly less than many independent <select> alternatives I've
seen, and the component itself doesn't have to worry about positioning,
styling, etc. because that's handled by lower-level components.

> Another place where “components” generally fall-over is when a component
> needs to act as a parent or container for arbitrary markup: yes, there’s the
> “slot” system but those are still defined and controlled by the component,
> not the consumer - even though ultimately it’s the consumer’s application.

With web components, slotted content stays in the light DOM and is therefore
controlled by the user. It's actually kind of a pain point when building them
because, internally, you _don 't_ have that much control over arbitrary
markup. (You can access markup through slot.assignedNodes() and style things
with ::slotted() but it's not what I'd call a first-class experience for
component developers.)

------
Hamuko
Why does it feel like JavaScript development is always accompanied with a huge
amount of emoji?

~~~
partyboat1586
I used to be with it. Then they changed what 'it' was, now what I'm with isn't
it and what's 'it' seems weird and scary to me.

It'll happen to you!

~~~
DJBunnies
Thanks, Abe.

------
rho4
The only component I want to see in a demo of any UX framework - be it desktop
or web - is the almighty tree table. I‘d like to see sorting, filtering,
column resizing and -reordering, including save / restore of the above. Row
(multi-)selection, striping, hover. Inline editing. Show me all other
components inside a row.

~~~
claviska
Tables can get quite complex as features get sprinkled on. I doubt any out-of-
the-box solution will nail it for all use cases. I'm not opposed to including
one in Shoelace at some point, but I'd want it to have an API that's capable
of handling the majority of [reasonable] use cases in an elegant way.

It's definitely high up on the list of components that are challenging to get
right!

------
jiofih
Little detail not mentioned: no server-side rendering possible at all.

~~~
1337shadow
I'm not really sure what you mean: I actually pre-render everything in
templates, when in webcomponent however I use the slot attribute which also is
an implemented standard now.

Anyway, that's the feature to pre-render everything:
[https://stenciljs.com/docs/hydrate-app](https://stenciljs.com/docs/hydrate-
app)

~~~
chrismorgan
Shoelace is using the Shadow DOM. You fundamentally can’t prerender that yet.
(Refer to my comment.) I’m a little surprised to see no mention of that in the
Stencil docs.

~~~
1337shadow
Actually, you can disable shadow dom on Stencil components, which I ended up
doing in my own code because it then nicely integrates with my favorite server
side framework, that still does most of the work.

What is it exactly that you can't pre-render ? That's not very clear to me.
You can put any kind of content inside your web-component tags:

<your-paragraph><p>your test</p></your-paragraph>

If the browser is recent enough to support TLS 1.3 (which we all want to move
on too don't we !) then it is recent enough to support web-components for
sure.

So, that's pretty much how I see it: browsers have to upgrade for security
reasons, if we're getting features like the ability to do some components
without having to load a fat frontend framework, components that integrate
perfectly with my favorite server side framework, then my question is why: why
should we not haz nice things ? we're getting them for free after all !
Without even webpack to make a 1MB bundle ! I'd like your help to better
understand what's the bad news here ...

~~~
chrismorgan
I’m not familiar with Stencil, but it _looks_ like the Shadow DOM switch is
targeted at the component author, as something that they will need to adjust
their code for, and thus I would _expect_ that it won’t be quite as simple as
just turning off shadow DOM, though it could still be straightforward, though
still something you’d need to _do_. I’m not sure. Other aspects of Shoelace
might also be designed with Shadow DOM in mind, though the couple of
components I’ve glanced at the code of seem safe; but interactions between
Shadow DOM and ID references (e.g. <label for>, aria-describedby) can be a
little fiddly.

I’m talking about the document becoming interactive and operative without or
before JavaScript is loaded. Shadow DOM is not part of the HTML serialisation,
so anything using Shadow DOM fails this test. Fixing this is what Declarative
Shadow DOM research project is about.

~~~
1337shadow
Confirmed that the shadow dom switch is available to the component author, so
they'd have to do two builds if they wanted to use both in different projects.

Agreed the shadow dom didn't seem ready for me neither, but I feel that we're
getting there, and meanwhile it's hopefully optional.

------
iRomain
Very nice library! Good to see web components taking of.

------
sheeeep86
I'm very excited about web components. One thing that I don't understand yet
is how server side pre rendering works in these situations. Basically the
elements need to be downloaded before the browser can render anything, which
will delay the page in it time. I guess if everyone was using the CDN then
these components would be cached for multiple applications. But they would
still need to be initialized and render themselves on each page load,which
could take long for complex components.

~~~
claviska
I'm no expert here, but Stencil is capable of SSR [1]. I believe you'd need to
install Shoelace locally and tweak a few configs to get it working, though.

1\. [https://stenciljs.com/docs/static-site-
generation](https://stenciljs.com/docs/static-site-generation)

------
girishso
That looks amazing. Using bootstrap or other css frameworks across different
frameworks (react, vue etc) is a pain. This looks like a good start!

------
yalooze
On mobile Safari I can’t seem to long press on any links to bring up the menu
for Open in background, Copy etc. At first I thought this might be a
consequence of how the toolkit was built but it seems its standard Docsify
behaviour. A callback to the old ‘disable right-click’ functionality in IE
that thankfully newer browsers ignored.

~~~
claviska
Good catch, I never noticed that. I'll see what's up with Docsify and submit a
PR if I can fix it upstream.

------
woutr_be
Very interesting, a team at my company recently started writing an internal UI
toolkit as well. The first stage would just be HTML + CSS (and maybe some
JavaScript), but the second stage will be web components as well, to make it
framework agnostic.

~~~
claviska
Maybe Shoelace can save you some time. Thanks for checking it out!

------
werdnapk
The drawer component doesn't seem to work in Firefox 78. Clicking on the
buttons to open the drawers doesn't do anything.

~~~
claviska
This was addressed here: [https://github.com/shoelace-
style/shoelace/issues/103](https://github.com/shoelace-
style/shoelace/issues/103)

Just tested with Firefox 78 and verified it's working now. You may have an
older cache.

~~~
werdnapk
Just tried again and yes, it works now.

------
progx
But where is the difference to e. g. UIkit? Only write in component-style
without div-tags and use css-vars?

~~~
1337shadow
Well Shoelace/StencilJS/WebComponents leverages browser ESM support and as
such is able to import scripts as-needed as you browse, you can see that by
leaving the Networking tab open in the browser inspector, and I believe that's
pretty nice - that's the kind of reason why webpack got chunk splits ...

You can probably achieve that with UIkit if you make one bundle per page with
webpack or something, but with web components such as Shoelace you get that
for free. So there's that, wether it matters to you or not is up to you of
course.

------
rawoke083600
Is it just me or doesn't any of the examples work ?

~~~
claviska
Seems to be working for most people. Are you using a legacy browser?

~~~
1337shadow
There's some polyfill for IE11, maybe it would be worth a try ?

[https://stenciljs.com/docs/browser-
support/](https://stenciljs.com/docs/browser-support/)

It seems it is necessary for browsers that have been abandoned and that are
never going to have TLS 1.3 support: IE11, Edge 16-18

Personally I'd leave it just to push users onto abandoning those browsers that
will never support TLS 1.3.

