Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Shoelace: A library of web components (shoelace.style)
294 points by alexzeitler on Jan 10, 2024 | hide | past | favorite | 110 comments


We at Microsft used this to build apps.microsoft.com. We're quite happy with the results. Shoelace is customizable, accessible, extensible, easy to use.


You at Microsoft don't use Microsoft's fast.design?


They at Microsoft don't use many of the stuff that we are supposed to use, e.g. see MAUI.


Also note, Shoelace was built by a Microsoft engineer, Cory LaViska. He left to work on Shoelace full-time[0] after it was acquired by FontAwesome.

[0]: https://blog.fontawesome.com/shoelace-joins-font-awesome/


We considered it, but Fast was missing some key components when we started building our web app.


This is nice and all, but when I see what the big companies do, I always have this cave-at in my head - "is this one of the teams with enough resources to boil the ocean?"

I.e. it's proof that Shoelace, in this case, is not inherently useless. But it's hard to get a hunch for how good it is to a mere non-corporate.

Gotta give props though, the apps site is fast and slick.


That's a fair point. Big companies do have the resources to go all out, but that doesn't always mean their solutions are the best fit for everyone. I think Shoelace is pretty neat because it's more approachable for folks who aren't part of those mega-teams.


Nice, that sounds like a good product! I will have a look. Thanks.


I'm not happy with any of the solutions to prevent a flash of undefined components. Has anyone given up on web components for that reason? Or is there a best practice for this?


Sounds like you might like the idea coined as "HTML Web Components": https://blog.jim-nielsen.com/2023/html-web-components/

You basically write all the normal HTML and CSS so it's loaded in right away. But then you also make use of the advantages that defining a custom element gives you.


That's a nice workaround but still just a bandaid in my opinion. Instead of a "flash of undefined component" you get a flash of whatever the vanilla html is before your web component was loaded. Now you have to adjust the vanilla html to look as close to your web component as possible, at which point you may just want to use vanilla html and css altogether and ditch the web component.


Use a loading overlay that will show for 0.25 seconds if you're that concerned about this


User delays of 100-300 ms is perceptible to the user. This is the exact issue we want to avoid.


And in that delay they'll see a loading screen


Yes, this technique sounds really good. Thanks for this.


You're welcome!

I've started moving to this technique from my earlier technique of putting a data-module on wrapping div components, where I manually had to deal with a bunch of stuff which HTML Web Components just do for you for free. Super handy!


How do we write this? I googled some tutorial and it seems it is still JS under the hood


It's basically just web components without the ShadowDOM implementation. I do it in some projects, but it comes with other drawbacks too.


Yeah like no slots.


Nested components are not playing nice with their lifecycles too.

Querying elements also becomes more complex.


That article makes a helpful distinction, thanks!


the doc site doesn't have this problem because it doesn't make a giant single archive of code that loads slowly on a single core. lighthouse doesn't even record the flash. most of the pages are getting 98/99 performance scores.

i'm sure if you webpack the crap out of it bundling hundreds of dependencies into the same parse, it'll perform poorly, but well, stop doing that.


It definitely does have this problem, on Firefox at least. Refreshing the page has a lot of layout shift as buttons render.


I did. I can't accept that as a user, so I'm not going to make my users put up with it. The simplest "fade" solution or adding a loading dialog is a huge pain and I'd rather write vanilla html/css/js if it will allow me to avoid that.


I usually hide the web components until they are defined using `:not(:defined)` CSS selector


That causes CLS which is also an issue


My apologies. By 'hide', I meant hide visually (through `opacity: 0`) that keeps the space reserved to avoid CLS.


Do I understand correctly, this only works when the size of the component is determined from "above" in the layout tree? That sounds not generally useful...


This is a solved problem.

You tackle it by doing two things:

1) use a bundler (rollup or webpack) if your code is big so it can be chunked and loaded quickly

2) have a loading spinner by default

Some developers have a dogmatic zeal against loading spinners, but users are very accustomed to them.

In fact, it's possible for websites to load _too_ fast, seeming unnatural to users (who at this point in time are very much expecting the flow to be request->spinner->load).


Do webcomponents not have build time pre-rendering or SSR?


Web Components in general: sure. But what Shoelace uses: no.

Specifically, Shoelace uses Shadow DOM and adoptedStyleSheets.

For Shadow DOM, there’s Declarative Shadow DOM, a way of serialising a Shadow DOM, which is extra work to support, but possible; it’s currently supported in Chromium and Safari, and last month Firefox landed an experimental implementation.

But the key feature and problem of Shadow DOM (in my opinion, more problem than feature) is how it isolates styles. You need to add the stylesheet to every shadow root, via a <style> or <link rel=stylesheet> element (and hope the browser is clever enough to deduplicate, which it should be in the latter case but I don’t think it will be in the former), or via adoptedStyleSheets, which is generally more efficient and allows shared mutation after construction (unlike the other approaches). Shoelace uses adoptedStyleSheets. Trouble is, that doesn’t work with Declarative Shadow DOM.


No, I believe it is the nature of web components that they can't be server rendered. I'm not talking about framework components like react, vue, etc.


Certainly can just depends on the framework used. I know 11ty can server render them. Astro.build supports lit as well.


Give me declarative adopted stylesheets!


this looks great. I'm puzzled by something though: why does it duplicate components that already exist in standard HTML5 (Button, Checkbox, Dropdown etc.)? The whole idea of web components is being able to augment what's already built in, not have to replace it.

Maybe it's for consistency (styling/behaviour). Either way, it looks really well done.


It doesn't duplicate, it wraps. `sl-checkbox` is ultimately a `input type="checkbox"`, but wrapped in containers and exporting uniform props. For example `sl-checkbox` is a container with both a checkbox and a label container in it. And it exports a prop `size` which takes the values "small", "medium", "large", which is uniformly provided across Shoelace input components.

It's a combo of (a) HTML lacks the features/ergonomics and (b) need to provide a clean-syntax API that extends HTML.


The only reason we have 10,000 UI libraries in the last 20 years is because we decided to keep default browser UI ugly and bare-bones for some reason.


That's a good thing in my opinion. Don't give me a set of 25 controls, instead make it easy to make my own. Because no matter what you include in default controls, I am going to need 12 more.


But the default set has been lacking for too long now too. Webbrowsers should really get together and make a new default set of Application-based UI controls, and make them a bit more beautiful by default. :)

Like datatables, rich-text editing, toolbars,...

MOST applications are just simpler CRUD UIs. Developing these is still too complex on the web platform.


Or: we as users can wish for the days of 90's web design and bring it back! The main content was so much more up front. Forms, buttons, and general layout were all the same.

And Progressive Enhancement has it that our bells and whistles gracefully degrade back to from whence they came.


> instead make it easy to make my own.

But browsers don't do that either. And you really, really don't want to make your own controls most of the time. Because: https://drewdevault.com/2021/06/27/You-cant-capture-the-nuan...


I think it's also because every site wants their buttons etc. to look slightly different to every other site's, because branding. Being able to stand out from the crowd is a feature.

Personally, I wish that for accessibility and other reasons, all 10000 frameworks would produce buttons with some kind of metadata that lets a user configure their own settings. But we're quite far off that.


Because browsers offer very little styling and customization options even for the handful of built-in elements. That's why every library under the sun tries to re-invent them again, and again, and again.

https://open-ui.org/ will finally help with this, but it's a very slow process.


Theming is at least one reason.


One can extend native elements, but the support ain’t there on Safari


I recently made an entire WebRTC p2p video player that worked seamlessly everywhere! Except iPhone Safari. And all iPhone (but not iPad!) browsers are Safari under the hood that couldn't do a few of the fundamentals needed.


Just this tiny polyfill, and you should be OK on Safari. https://github.com/ungap/custom-elements


I love this component set. The maintainer, Cory, cares a ton about accessibility and quality and it shows.

They're built with Lit too :)


I didn't like that the components are all web components with their own shadow Dom inside. Makes styling really hard and didn't work with tailwind for example.


Not just that, but it basically makes the library incompatible with serverside rendering a la Next.js. We actually explored using Shoelace for a project but ended up having to choose something else instead because of this.


True, it completely relies on client side rendering, and it's impossible to render it server side. With disabled Javascript it doesn't show anything at all.

I would really like to use it, but using it feels like limiting your options much more than necessary. Even the CSS-in-JS based libraries (like React MUI) allow SSR to some extent.


What did you end up using?


We settled on Chakra (https://chakra-ui.com/). Although we also abandoned our ambitions of a Next.js migration, so... I guess it didn't really end up mattering all that much anyway.


Thank you


I guess the advantage is that you can drop them into any HTML page and they look and work correctly. And you can control them with plain JS, like `document.getElementByID(dialogId).open = false;`


Probably, from my perspective (using a frontend framework) this doesn't sound too helpful though.


I've used these in the past and they are really well done.

Also the developer now works at Microsoft and they are using it so at least it has a major backer.


Cory (the creator) actually works at FontAwesome now. FontAwesome purchased the library ~1yr ago and hired Cory to work on the library full time as well.

https://blog.fontawesome.com/shoelace-joins-font-awesome/


I've used this, works great.

Good option for those who prefer vanilla web components.

Only hangup I ran into was the event/callback based API for some components - promises would have been more convenient.


I'm impressed with the breadth of Shoelace's offerings, particularly its emphasis on accessibility and framework compatibility. For a project I'm working on, which involves creating an interactive e-learning platform, components like adaptable quizzes and responsive drag-and-drop interfaces are crucial. Could Shoelace be extended to include such interactive elements, maintaining its accessibility standards?


Haven't done frontend in a long time, but how is this different than something like Bootstrap? Is it the fact that it comes also as a React & co library and you can customize properties of a 'component' easier than building your own wrapper 'component' to modify properties which are set via 'data' or 'css' attributes? I guess this leads me to the next question, I saw in a recent project on my company's Github how everything was done with 'React-Bootstap', which to me looked very weird, that in every Jsx component there was barely any HTML tags, but only smaller components from this bootstap-react library, even for simple things like <h1>s. It all looked like a mess to me, but maybe my views are from older times.


It's like Bootstrap, but different. Main difference: it's based on Web Components and Javascript, Shoelace won't render anything without Javascript, without the possibility of Server Side Rendering (Shadow DOM requires Javascript)

Bootstrap got kind of stuck in the past. Vanilla Bootstrap is only really usable without a modern frontend framework, as it comes with many Javascript snippets that make the controls interactive. But it's just not really compatible with other UI libraries like React, Vue, etc.

Also Bootstraps feels quite antiquated from a user perspective. And for theming bootstrap you need to go through Sass hell.

I still use it for server side generated HTML, because it's really easy to use and just works.


Thanks, makes sense


Like bootstrap it's a set of standard behaviours and styles.

Bootstrap basically takes standard elements and when you add CSS classes and data properties, it styles them and adds some JS behaviours.

Shoelace builds HTML custom elements, using CSS variables for controlling the style, with the JS baked into the custom-element code. And Shoelace uses the shadow DOM, so any customisations do not "leak" outside of your components (although this has its own implications).

Custom elements basically do the same as React/Vue/whatever (reactive properties, slots etc) but in a manner that's built into the HTML spec and into all browsers. (React/Vue et al also have mechanisms for building your components as custom-elements, but you're then adding the dependency on React/Vue when you reuse them - although Shoelace has a dependency on lit.dev, as the actual custom-elements spec is quite low-level).

But Bootstrap and Shoelace are essentially solving the same problem - a reusable design system - but Shoelace does it in a way that's already built in to browsers and arguably cleaner to use.



Finally a component library with trees and resizable panes!


Sencha (ExtJS) has been around for 16 years...


Haha I know right? Can't wait for us to circle back towards sensible UI frameworks again.


Just missing a (multi) file upload widget in general and an image upload one in specific.


I like Tailwind, so I’ve been using Preline and been happy with it.

https://preline.co/docs/index.html


I didn't try it out, but usually I'm unhappy with Tailwind based libraries. It just doesn't really fit the concept of Tailwind to use it for a UX library. On one hand those libraries are just a handbook of HTML snippets to copy&paste. On the other hand many of them need some support library, that does some magic in the background that's hard to understand.

The only one I liked so far was shadcn, which is more like a code generator for creating Tailwind based React components.


https://RTCode.io is built on Shoelace 2 today.

Just hover over that middle divider between the input>|<output panels to get a feeling of how customizable it is.

Also our menus do not follow their keyboard navigation logic at all and adds support for disabled, hidden, inert elements, as well as selection by typing the first letter of menu items.

All of these are possible because the author knows what NOT to do with HTML custom elements.


Quick feedback.

I'm on Firefox and scrolling your site is really slow and also fans is spinning up (I've plenty of RAM and CPU power).

Something on your page is degrading performance (for me).


have been following the development of this very closely for this library, and love the fact that we can script load individual web component in html as bare bones.


Can you please elaborate on what this means ?


Add the script tag to your page for any of the components and you can use them. No building, compiling or initializing anything.


exactly, and pair that with css variables for customizations if needed for ad-hoc projects/prototypes or full products


On my phone, the whole page is covered by the left side menu. Tapping on the burger doesn’t hide the menu either. Not a good impression from a web design library.


Hilarious how the basics keep getting broken despite the huge amount of collective effort to reinvent the basics


Despite? Because of.


What phone are you using? It seems fine on my old iPhone mini.


Iphone 6S running 14.3.


That’s before Safari added better web component support. I would expect many sites and apps to not work at this point.


14.3 seems more like "try to degrade gracefully" old rather than "won't support" old...


It’s extremely common to support the two most recent major versions, especially for iOS. It’s great if things work on iOS 14, but it’s been explicitly out of support for over a year in a vast number of organisations.


That's the well-established expectation for iOS.

The web has a pretty different set of expectations, one of the reasons for its success.


Not these days, where most people are using evergreen browsers and iOS users upgrade very quickly.

Take a look at the defaults for browserslist, for example:

https://browsersl.ist/#q=defaults

It just barely supports Safari 15, on iOS only, and that’s likely to go away imminently because it’s under 1% usage.

Browserslist is used by a huge proportion of web developers and the tools that they use, with millions of downloads a week. It has nothing to do with native apps and everything to do with the web.


Whatever it requires to hide the menu, that a 3 years old browser doesn’t have, can’t possibly be essential for just a documentation page.


It’s an 8 year old phone … iPhone 6s was released September 2015…


The issue here is the version of the webkit engine, which ships with iOS and that is 3 years old. Anyway a docs page is basic, it should be compatible regardless.


Works for me, 15.7.9, so updatable.


I'm looking for a library of web components that:

1) Uses slots for composition

2) Does not use CSS-in-JS

3) Lightweight

I understand that slots imply shadow Dom, and then shadow Dom usually means adding/adopting stylesheets into components, and that means css in js.

But there's also ::part that allows piercing the shadow dom. Is there any library that uses it?


https://webcomponents.dev/blog/all-the-ways-to-make-a-web-co...

Yet, they are all Tools, and you don't learn a Technology by learning a Tool, or do you become a Writer when you learn Word?

``::part`` is part [sic] of the Standard, it doesn't require any tooling.

CCS in JS is your choice

https://jsfiddle.net/WebComponents/znbgf726/

https://i.imgur.com/inJAbQW.png


The CSS doesn't need to be in the JS. You can trivially just fetch the static CSS file in JS then have the content adopted.


Yeah but flash of unstyled content? Plus you need to somehow adopt only related parts? Selectors wouldnt match easily necessarily, e.g. decision to adopt :hover selector must be made somehow


I think this library does what you want: https://shoelace.style/getting-started/customizing#css-parts


I guess it’s most-but-not-all part that got me confused. The are parts re-exported Manually? I guess that works


this seems like a great library, but it is missing a date picker. it’s hard to find UI libraries willing to take on the date picker, i guess because native pickers, esp on mobile, get the job done?


Browser native date pickers are usually good enough and meet accessibility requirements these days.

Unless you have fussy designers or PMs who insist on artisanal NIH components for everything just because.


I've been using this in conjunction with Unpoly. Very refreshing to develop with no build step and good old server-side templates.


These all look the same. Are there any designers out there who do not follow the "current thing" and can actually think for themselves?

I want an opinionated component system which do not look like the others.


Serious question: if you're building an application, why do you want this? It used to be a huge thing to build Apple, Windows, Motif, whatever apps closely in accordance with their interface guidelines and idioms, but for some reason on the web everyone seems to need an idiosyncratic, opinionated set of basic controls.


I agree with you and I am sure I am not saying anything new, but the fact that on the web content, presentation and marketing sites heavily outnumber webapps, and that one needed to stand out - even if superficially - from countless other options, caused a much larger emphasis being put on customizability, looks and originality which didn't stop at layouts colors and typography, but seeped into interactions. So a lot of jobs got created, lots of users suffered from slow, confusing and buggy UI/UX but at least lots of originality and prettiness was had :)


Oh for sure if there was a web platform look, I would happily oblige and use that look. The point is that there isn't one so in that case I would rather have something different.

If we had gone down the path of smart documents instead of web apps for the internet, we would have had a better time for sure.


For what it’s worth all the components expose CSS parts that let you customize each component in detail.


I don't see that these components use part/exportparts feature to do that. Am I looking at it the wrong way? Or do you mean that customization happens via CSS?


Yeah, sorry, it's using CSS parts for customization. So if a component is made up of multiple nested containers, you can target the inner containers with ::part(name).


No data tables in library? Other than that nice work!


These look and feel great! Will give it a try.


Oh wow, I love this. Incredible work!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: