Plug and Play Design Systems with Georges Boris

Georges Boris joins us to share two new packages for theming and stateless widgets with minimal boilerplate.
January 16, 2023


Hello Jeroen. Hello Dillon. And what are we talking about today? Today we have a guest
with us and that is George, George Borys. Welcome. Hey folks, I'm glad to be back. And
we're going to talk about what you released recently which is called Elm Widgets. Can
you explain to us what Elm Widgets is? Sure, Elm Widgets is a collection of widgets that
you can use in your Elm applications. It's similar to what you would expect from something
like Bootstrap or maybe Material components, things like that. But it's aiming at focusing
on the things that make Elm, right? Like doing a good set of APIs that are still type safe
and doing that in a way that you need the least boilerplate code possible. So focusing
on stateless components and how can I say it? Well, using kind of like what you get
with the platform like by itself so that your Elm side of things is as clean as possible.
Make sense? Yeah. So you released this package and the full name is uncover-co slash Elm
Widgets just if people are trying to find it. Yep. Yes. Uncover is the company. So this
package is like one of the open source initiative ones. Yeah, that's great. Is Bootstrap still
cool George? Or is it becoming cool again? What inspired you to create something in this
sort of philosophy of like a set of plug and play widgets? What motivated you to do that?
Were you solving a problem for yourself and your team or for the community? Yeah. It's
a good question. I would say no, but at the same time, maybe yes, because so many people
use it and I know that it's constantly getting updated and using kind of like the new cool
things. So the new, I believe that there is like a pretty recent version of Bootstrap
that is more like tailwind or something like that. Maybe I'm saying completely like a wrong
thing here, but at least like the look and feel is a lot more modern. But yeah, like
for my own company, we wanted to create like a set of UI elements for us to use in our
design system. And there is a lot of work when you are first doing that in a new project.
And most of the time you're not actually getting the value of like spending all of the time
building the same kind of like so reusable components, like a date picker or a way of
like validating some input text in a really, I don't know, predictable way of like accessifying
a mask for an input or anything like that. So I started browsing in Elm packages and
there are some stuff there, but most of them are kind of wrappers around XG scene, non-Elm
libraries like Bootstrap, like Booma. And most of them are not even the modern ones.
So like it's an old Bootstrap, it's Booma, which is not like, I believe that this is
not like the thing that people are using the most right now. There is like a material one,
but then like you get into this mess of like, I need to import JavaScript and the JavaScript
will interact with Elm in some way. And there's like, I don't know, it gets a bit complex,
I would say. So I thought that maybe providing something more simple for the community would
be good for people to just get more, get productive faster, you know, because I noticed that the
Elm community is really tech savvy in a lot of ways. I constantly see people talking about
like this new data structures or new ways of dealing with, well, data basically and
types, but the UI, it's not forefront, in the forefront a lot of the times. So if you
could just like plug and play something that looks nice and feels nice, and maybe it's
like, it's accessible, that could make the like Elm apps feel better as a whole. And
that would make Elm look better. And that for me is like a complete win.
Right. So do you view this as a package to, excuse the word, but bootstrap Elm projects?
Sure. Yeah, I hope so. Like the whole idea is that Elm widgets focus on kind of like
units, right? So you can just like use Elm widgets for this one thing that you're trying
to just like throw it out there really fast. So if you have an existing app and you just
want to use like a slider, please just like use Elm widgets. And there's like a customizable
slider that you can use there. There's like some validation, but if you are bootstrapping
something new, maybe you use Elm widgets for most of the, like this common UI elements,
right? And in that subject, I tried to make Elm widgets be, well, at first I didn't try
to make Elm widgets be a competing strategy with anything that already existed, like Elm
UI or Elm CSS, or like there are a lot of different like really quality things in the
Elm ecosystem. So I just wanted Elm widgets to be something that can live alongside them.
But if you are starting a new application and you like imported Elm widgets and you
are, I don't know, like you want to just like do a small layout thing, which is something
that is not like the focus of the library. We also included a few helpers that like there's
this container widget, which is kind of like this small subset of what you would get with
Elm UI that maybe it will get you farther using just Elm widgets and without you having
to like, I don't know, like pull in something else just to do like the layout or something
like that, right?
It feels a lot like the Tailwind philosophy of like providing a constrained sort of system,
right? A few utilities that let you have layout utilities and a standard for the sizing units
and some baked in opinions.
Exactly. It's definitely an opinionated set of widgets. And this also plugs into the way
that we do teaming using Elm widgets because we also released this another library called
Elm Team, which you need to use if you want to create your custom team for Elm widgets.
So once again, it's uncover co slash Elm theme, right?
Exactly. Yeah. So we bake in a default team with Elm widgets, but if you want to create
your own, you will probably import Elm team and create a custom team there. And the thing
is that Elm team is a really constraint based team setup. So there are like this small number
of variables that you need to define and everything will follow that pattern. So yeah. So Elm
widgets is just like an application, not an application, but view functions on top of
Elm team.
Right. So that would be similar to in Tailwind defining your, your palette. And in fact,
you have a little NPM helper package to help you build a theme using your palette from
Tailwind, right?
Exactly. Yeah. The NPM package. So Elm team, the way that it works is it provides a set
of CSS variables inside the scope of your application in every single value of like
colors or like the, the phone families, they are using those variables just like you would
do with Tailwind, right? Like when you create your Tailwind config, you're actually defining
a bunch of like CSS variables that Tailwind uses underneath each of its classes.
So what I did is that I created an NPM package, which is a Tailwind plugin that you can use
so that you can define your values using Elm team, but they are also available in your
Tailwind. So you can just like mix and match. Oh, I, maybe you use like the component from
Elm widgets, but you are pretty used to doing layout with Tailwind or you're not, you don't
want to do like create all of your components using Elm widgets. You can create like just
reuse the buttons, the, the, the, the form stuff, maybe a tag or something like that,
a pop up pop over, sorry, but everything else you can just use Tailwind and that's fine
because it will get access to your, to your values.
So do you define the same number of variables as Tailwind?
No. So Elm team focuses on color and font families only. So it, it doesn't focus on,
I don't know, like spacing or in like Tailwind, there's a lot of stuff. Yeah. So it's, it's
kind of confusing a bit because well, Elm widgets is using Tailwind underneath. So if
you actually go to Elm widget source code, you see that Elm widget styling is done using
Tailwind using like Elm teams Tailwind plugin. So it's kind of like this whole ecosystem
of packages that are intertwined in a bit. And I did this just because I really wanted
Elm widgets to be a community package and Tailwind is something that once you know how
to use it, you do like my Tailwind TSS declaration will be the same as Dillon's. So if Dillon's
wants to, if Dillon wants to create a new widget, he can just go there. He will follow kind
of like this really fixed pattern of defining a few things and it's fine. It will look the
same. The API, it's really, every component has the same API basically, or at least like
the same structure. So, so yeah, I felt like Tailwind would be like the right choice for
the package itself to be more approachable for contributors.
That's very interesting. So I, I remember back in the day I made my fair share of apps
with Bootstrap, Twitter Bootstrap and, and it was, it was great, you know, it was great
like throwing together some widgets and you make an app and you can get really comfortable
building things with that and move quickly. And, and then in more recent years, I've really
started to love the Tailwind workflow because first of all, there's so much love that the
creators of Tailwind have put into the small details of getting the design system right.
And the, the basic defaults for the spacing and the rounding and the different units that
like the, you know, how quickly the units grow for P2 to P4. And there are so many details
they put into all these little details about fonts and all these things that most people
aren't going to think about. And then you can build a site that looks great, but it's
easy to build because you don't have to have an opinion about a lot of things that they've
put into it, but you can if you, if you really want to. So that's been an interesting progression
for me, styling things to go from Twitter Bootstrap, because I think one of the things
with Twitter Bootstrap, one of the reasons that it's fallen out of popularity is that
people could start to recognize a Bootstrap site and then they would stop having that
branding differentiation and people want to build their brand. They want things to look
professional rather than a cookie cutter site that looks like anything else. And they want
to have their unique brand. And of course you can theme Twitter Bootstrap pages with,
you know, custom variants and things, but, but you're limited in, in how you can theme
it. So this is an interesting twist with, with Elm Widgets and Elm Theme with how you're
kind of like using some pieces of Elm Tailwind, some of the Tailwind philosophy, and then
some of this more Bootstrap philosophy where you're like, here's a button. But do you,
do you think that that hybrid approach, does that like avoid some of the pitfalls of getting
stuck with a cookie cutter site that you can't build with your, your brand's custom styles?
Or does that, does that allow you to, or do you eventually outgrow it and need to do something
more custom?
Well, here's the, the, the strategy, at least for now, I'd say that like becoming something
that is easy to recognize. First, if that's the case, then like props to Elm Widgets because
it's a success, you know, but sometimes you just want to get things done and there's just
so much opportunity to get lost in like this small decisions of something that is not your
main thing to do when you are not trying to, to look like a, like the cookie cutter that
you said, like, like this, this standard way of doing things. But at the same time, I,
I definitely have been someone that, that like didn't want to look the same and like
created my own thing like over and over again. So
Congratulations. You have done it again.
Yeah. The thing is that for Elm Widgets is not just look and feel. There is like this,
this whole thing about creating this nice API for, for Elm, right? And I feel like these
APIs are valuable despite the styling. So my, my idea is that Elm Widgets can eventually,
and I actually started doing that, but I kind of like roll it back before release and I'll
try to make it better before actually releasing it, but make Elm Widgets possibly be a, how
can I say it? Like, like headless UI. So an un-styled UI that you can still use the API
for validations, for all of the, the, the nice Elm APIs that use the browser itself,
but you can still style it as you see fit because in the end, those are just like view
functions that are receiving classes and you could pass in your own tailwind classes, or
you can pass in your own, like, I don't know, just like normal style tag or like style attributes
or anything like that and make it your own. I don't know. I feel like there's a, a, a,
a, how can I say this? Like a gradation? I don't know. Like a, a, a possibilities here.
Like you can just like do the really easy way. Maybe we can get so far by using Elm
team and making the, the colors and the fonts, something that looks like your brand. So that
might be sufficient for a lot of the, the, the use cases for different companies because
of a few things like Elm is not that used. Elm Widgets is not like that used. So people
won't recognize it like from the get go. But even if it was, if you are doing like the
admin of your own company and you just want to get like, make things like appear in the
screen, hopefully you just want to get stuff done, you know? And then like the, the, the
last final step, maybe you want to go that extra step, not for every single pieces of
your UI, but maybe your bottom, you want to use like your bottom in a way that like the
API is the same, but you want to make it really customizable. That's fine. Just go the headless
UI route, you know?
Right. So maybe in a, in a context where you have like a large company with a very particular
brand and they have designers trying to curate the full experience of what the UI looks like,
it's not the tool for that because it takes certain opinions. But if you're, if you're
able to not make, you know, not need to micromanage every detail of the UI and just say, I want
a button and I don't need to control exactly how the button looks, then it might be a really
good tool.
Yeah. And I hope to not just by myself, but like as a community to kind of do the same
thing that you mentioned about Tailwind, which is kind of like grouped together this set
of nice, nice, I don't know, like community knowledge about good design patterns, accessibility
patterns, and maybe even like, I don't know, a few styling decisions. I'm already piggybacking
on Tailwind for most of that. So if you are using the containers and the text and the
title, like those things that are really basic, those are, those elements are part of Elm
Widgets because they are kind of like a way for you to be consistent with your, with your
team, whenever you are using it.
But if you were using Elm Team with Tailwind CSS, you would get the same thing because
it's using Tailwind underneath as well. So yeah.
Right. So you can, you can use this with an app that's styled with Tailwind, which is
really interesting because then you can, you can sort of opt out of a certain widget style
and just drop into Tailwind and say, I'm going to use this one Elm Widget widget, and then
I'm not going to use this other one. I'm just going to do straight up Tailwind. And that's
also true for if you're using Elm CSS, if you're using Elm UI, right? So there's, talk
a little bit about that and how, how did you build it to enable using it with all these
different tools? Because there's often a problem in the Elm ecosystem that like the composition
problem. You have like Elm UI and you have Elm CSS, and then you have Elm, like accessible
HTML, but then you need like Elm accessible CSS, HTML, and then you have Elm CSS with
context and Elm UI with context. But then how do you use that with Elm accessible CSS
with context? So how did you avoid that like composition problem with, with your design
I have to say, like, I'm just starting to dabble into like using Linux and what you
described to me, like, it seems kind of like the same hell, but, but yeah, like the, the,
the thing that I, I tried to do was just go the, the most compatible way possible, which
is just like go the, the pure HTML. Like eventually every, everything needs to talk to an HTML
and like convert to and from HTML, right? So Elm widgets, all of the functions, they
return like pure Elm slash HTML. So, so yeah, like Elm UI, you can use, I believe it's like
the, like HTML function or from HTML or something like that. Yeah. Elm CSS is like from unstyled.
So every one of them, they, they, they are able to, to talk with Elm HTML in some way.
The only tricky thing, especially for Elm UI is that I'm not like a huge Elm UI user.
I really liked the approach, but I have, I don't have the experience using it. So for
Elmbook it has been like a challenge sometimes because there are some unexpected things that
happen because I believe that Elm UI uses a flex box for most of its like parent elements.
So I don't know if like CSS, you know, right? Like it's, it's a funny way of doing things.
So maybe a parent changes how things are like the rules underneath it in some ways. So there
might be some, some cases where you get unexpected results because you are placing an element
inside a parent that kind of like changes the rules. But most of the time, Elm widgets
provide, well, all of the time, Elm widgets provides you with like a single Elm element
and the rules underneath it are pretty well defined. So at most you get something that
should be, I don't know, like full width, be scratched to the left and you just like
fix it and that should be fine.
Right. I've experienced that before as well with like Elm UI where if you try to put an
HTML element within, you know, an Elm UI row or column, it might not do what you expect
or like vice versa. If you try to put Elm UI things inside of like a flex box, row or
column. So things like that might, might have some unexpected results, but otherwise it
generally is interoperable. So, so you, yeah, like what, what is your philosophy? Like you've
talked about stateless view components and you've talked about how your theme sort of
is trying to reduce boilerplate and you hinted at that it's using CSS variables. So like
how does all that work and how does that like reduce boilerplate for the, for the developer?
You know, yeah. And I would also like to ask why do you focus so much on stateless? Maybe
let's start with that.
Sure. So for beginners using Elm, I'd say that the whole plugin messages and trying
to compose like pages and like sub parts of the page and making like this, this, I dunno,
like this many work across different pages. Those things sometimes get, get to be unusually
hard problem to solve at first. And that can be frustrating. Right? So it's, it's kind
of funny to say stateless because the components, they like the DOM, it's stateful sometimes.
So if you are using input, so the inputs by itself, it's kind of like holding its internal
state and Elm is just like doing this IO to the DOM. Right? So it's communicating with
the DOM. When I, when I mentioned stateless, I mostly mentioned there are no messages,
like there are no, there is no internal state of a component that the component itself is
managing. So all of the components, they are just like receiving some message from the
DOM itself and then giving it to you so that you can like retrieve some, something, and
then you like return the same value to the DOM and that's it. But the, the thing is that
I wanted to still, to, to still be able to, to plug into that, that pipeline of communication
and a really useful way of doing that is by using custom decoders. So not just decoders,
but basically plugging into the decoder pipeline. For instance, the HTML input elements, they
provide you with a lot of like nice native validation methods. So you can define like,
a max length or a min length. So for your input, but you can also define a pattern using
regex. And so, and the, the browser actually gives you what, what validation actually failed
and sometimes even for what reason. So if we can plug into that API of the browser,
then we can give that to the user and it can just show you that, that output, right? It
can kind of like do this native validation of the, of the, the, the input without you
to, to do that inside your update cycle.
Yeah. When you say that the browser gives you that information, it gives you the validation
error. Do you mean that it gives you, do you mean that it gives you that inside the custom
events or the, the events?
Yeah. So each element, like if you, if you have the like input element, for instance,
it has this valid validity property and inside validity it has like all of this possible
errors that you can receive, like that, that can be true or false based on the attributes
that you're giving to the DOM. And it's you, it will show you, well, like what is the reason
that input is not, it's valid or not. And not only that, it even gives you this validation
message, but like, even though it was kind of like interesting, I ended up not using
it because the validation message, it, it was kind, it was kind of hard to, to make
sure that it was talking about the same error that you wanted to display. Like there is
like this priority that the, that each browser can decide, like you are wrong. Like your
input is wrong because of like three different reasons at the same time. The, but the validation
message you can, we can't actually control like which message will pop up. And sometimes
you just want to, to show like the, the, the most important error or something like that.
And, and yeah, like for, for cross browser, like compatibility, I decided to not go that
route, you know?
Yeah. Do you use the, I believe there are some like CSS pseudo classes for validity
of input elements too. Did you opt to use that or not?
I, I opt to not use that because, yeah, because I dunno, like I felt like this should be a,
since you have the errors at your hand and it's pretty easy to just like use them, it
would be awesome if the user could like choose if they wanted to, to show something to, to
be really intrusive or not intrusive. That's right.
I think so having done a deep dive myself on form API design for Elm with this stateless
mindset and looking at, you know, decoding events and things, I, I think you arrived
at a good decision there because essentially like, so this is an interesting approach you've
taken because you're, you're using these events coming from the platforms validation API,
but you're not using the CSS piece to determine if it's valid.
I think that probably gives you more control over when to show validation errors because
the problem with using like the CSS pseudo classes for validity is that you have to use
the exact platforms behavior on deciding when to check validity. So do you, so do you want
to show something as having an error before the user is even focused to that input element
because it's invalid because it must not be blank. And so suddenly you open a new form
and everything on there is red because it's not valid yet because it must not be blank.
That's frustrating. And you, you want to have fine grained control over when you present
validity errors or do you do that the second they focus it or do you do it after they've
typed something that can also be frustrating in certain cases or do you do it after they've
blurred it or do you do it after they've tried to submit it? So you want to have fine grained
control over these things and there's no one size fits all answer to that. So I think that
what you've arrived at is an interesting happy medium where you're using the platform there,
but also like, Hey, we can't use the platform for this part of it because it doesn't give
us the fine grained control that we need to have different possible behaviors here. So
do you use for stateless, you've talked about a few different pieces of stateless. So there's
the one piece of you're trying to avoid having view components that own their own state,
which you know, I think is a great philosophy. I'm a hundred percent behind that. I think
that's, is that influenced by Evan's Elm sortable table sort of mini writeup that he had in
that package?
To be honest, no, but that was a, a posthumous influence. Like when I started talking, talking
about this package with a few people, they mentioned this package and then I went to
it. It's like a really valuable, like learning resource. But to be honest, it's, it's more
like I've, I'm not like a really old Elm user. Like, well, it's been two years now, so it's
not like I'm not that new as well, but I, I definitely bit the bullet of trying to do
the whole like deeply nested Elm architecture and like do the, I dunno, like reinvent the
wheel like a few times. So I just wanted to, to be able to not do that right here. And
at the same time, I feel like in the Elm package registry, we have quite a few different like
complex packages. And most of the time the complexity comes because like you have to
understand this, like they're exposed API. Sometimes that these API is kind of like exactly
what you want. Sometimes it's, you have to kind of like understand the meta model. And
I just wanted to focus on the, like the, the most basic thing that you, you, you could
need and like, and that, that constraint it's, it's kind of useful because it, it makes me
clearly decide in one direction or the other. For instance, like for the outcomplete widget,
I, I just like took a look, like can I do an outcomplete using like just a HTML right
now and I can't, it's not that great, but like you can do it using lists and like input
lists. And, but then again, like we have this pretty great package in the, the package registry,
which is called the user is confidence men zero two, I believe like old too. And the
package is called select. So I'll select is actually also an outcomplete thing. And it's
like a bit more stateful than, than widgets. And I'm glad that both exists, you know, like
you can use widgets thing because it's sometimes simpler, but if you want more control and
you want to, well, just go use this other package. And I'm glad that both both exists.
And I actually, I really want to, to maybe, well, this is another ambition, but like since
own widgets is kind of like a big, biggish, like a largest concentration of different
things that you can use for your own application. Why not like in the documentation website,
the own book thing, why not even create pages there for something that it doesn't do? So
like shards, maybe you want to do a chart or maybe you want to do the, like this fancy,
like sortable table. It would be awesome if people could use it as a central place that
they would look to just like figure out how to do these things, you know? And I would
put them like, I would link them to like the best package or like the, the most widely
used options for each of them. Right? Like, so you'd get like Elm visualization, Elm charts
and like Elm select from Confidence Man and et cetera.
I can already imagine a lot of disappointed people like checking into Elm, which is like,
Oh, does it have charts? Yes. It has a reference to charts. No.
Well, I can make it like a different section, like community stuff.
Yeah. That's, that's a cool idea. I like that process of saying, you know, almost from first
principles, like this is my design goal. This is the outcome I want. I want somebody to
be able to like basically Elm install this Elm widgets package and then add the global
styles thing and then build stuff and, and, and not limit yourself to like, yes, it's
not a charting library, but I want that user who maybe they're building their first Elm
app or maybe they've just never used charts before and you want them to have a good experience.
That's, that's really cool. Yeah. We, a while back, we, some of the people
in the Elm community discussed about this hive knowledge that we have, like we eventually
everyone has it, which is like the patterns that we use or the packages that we go, that
we go for. And I dunno, maybe sharing that hive knowledge in this small niches is a good
way to go as well. Right? Like, so even if you're not using Elm widgets, maybe the documentation
it's, it's it's valid for you because you can go there and just like browse to different
stuff. Yeah. I found the accessible HTML package,
a reuse one that's in that sense, not in the hive mind sense, but like you just go through
the, the API and it tells you about all these accessibility problems and how you can solve
them even if you're not using the package. Like it's really useful just to go through
those documentations. Yeah. I, I was super inspired about Elm accessible
HTML and the accessibility part of Elm widgets is something that I really want to focus on
next because like everything should be accessible because like I'm not doing anything crazy,
like I'm not doing anything that the DOM doesn't do, but I want to go like the extra mile and
I dunno, make it the best that it can be by itself. And I just want to give a public thanks
to Tessa because like not only Elm accessible HTML, but I'm using another package of hers
called Elm palette that, that for the Elm team thing there is this team generator thing
in the documentation that I'm showing all of the contrast ratios and how accessible
is your, is your team. And that package offers were, was super useful for doing that.
So when somebody's adding this in, I've been thinking a little bit about like performance
with CSS and JS type things. And so this is something that's on my mind. So like I know
that this is a pretty vanilla CSS approach in many ways, except that you do, you add
the global styles. And so it's, it is kind of CSS in JS in the sense that you use the
Elm code to insert the style sheet that it uses for all the CSS. Is there a way to just
include the global CSS as a style sheet? Have you considered that or is that not a priority
for you? You mean having it available somewhere that people can just like insert it in, in
a different way, like just the header element or something like that. It should be pretty
easy to do and like plug into the CI. It was just not like a priority for getting the library
out there, but it should definitely be something that is doable.
I'm curious, what would be the benefits of doing that?
Well, there's an article I'll link to and at some point, actually Jeroen, I would love
to do a deep dive episode on this topic and explore more, but there's a, there's a blog
post by a maintainer of a popular CSS and JS package in the JS ecosystem about why we're
breaking up with CSS and JS. And it talks about the performance burden and the performance
optimizations you can get from using raw CSS and how the browser is really optimized for
that. Now, I mean, that said, like, I'm sure you can just do like a, a lazy style element
and maybe, maybe that's not a performance issue. So, cause CSS and JS is different because
you're constantly changing the style nodes and re-computing things as the styles change
in the children layouts. Whereas if you're just inserting a global style, it might be
very different cause you can just have a single lazy style node that doesn't, the elm virtual
DOM doesn't ever have to touch again. So maybe that's not an issue, just thinking out loud
here. Yeah. So, you know, another thing that comes to mind with it is like the bundle size,
but maybe it's, maybe it's pretty modest because I can definitely imagine like your loading
widgets are really nice and I've definitely copy pasted some really ugly CSS animations
and like had a lot of trouble, like maintaining these little bits of animation code just to
have like a loading widget. I can imagine like just, Hey, just install elm widgets and
then use the loading widget there. Cause they look really nice and you don't have to think
about it. So yeah, I'd be curious to look at the bundle size implications for just using
one widget, if that would be worth the trade off there.
Yeah, no, this is definitely something that I've considered. The size of the CSS, since
I'm using tailwind and tailwind is so optimized for a lot like reusing code and like it's,
it's really small. I believe like the, the whole, like the whole thing is like, it's
kind of like six K like a six K something like that.
You mean all of widgets, all of elm widgets?
No, no, no. Just like the, the CSS needed for all of elm widgets. And I could do the,
the whole like splitting up components in different styles, but then it might get like
easily it will get larger if you like import like three components maybe. Right. Yeah.
So this is why I haven't focused that on that so far, but like for something like the, the
loading stuff, it makes sense. But at the same time it it's, it's such like, I don't
know, maybe if someone wants to use just like the loading and it, it makes sense to access
by itself, maybe there should be another package that is just like pretty loaders. And so that's
Yeah. That sounds very much like what the, the problem they had with lodash in JavaScripts.
Lodash is too big. Okay, well let's split up every function into a separate package.
Yeah, right. Exactly. Fortunately, it sounds like it's not too big, but yeah, with, cause
there's definitely a burden on the user too for splitting everything up. So you have to
add the global styles for everything you include. And at that point you, you've broken that
philosophy of like minimizing boilerplate. So there's, it seems like you've made a reasonable
trade off there.
Okay. I want to, I want to geek out a little bit, not with my knowledge, but, but I want
to, to know more. So Elmwitches is full of stateless elements and some of them, I was
very surprised that they could be stateless. The one that I have in mind, but maybe you
have others is the modal where you can show a modal when you click something or when you
do an action and then it suddenly shows up. And I, I had a lot, a lot of trouble understanding
how you can do that without state. So maybe could you explain how that works? And if you
have other funny or interesting elements like this, I would love to hear about those.
Sure. Well, it's kind of HML plus CSS trickery the way that I'm doing that. And it would
be fine. Definitely. It would be fine for non applications. And I'm just hoping that
it's fine for applications as well. So the way that I'm doing it is just by using a checkbox
with a label being somewhere in the DOM and the default behavior of when you click a label,
is that you, at the same time, you kind of toggle the checkbox that the label is for.
So it's the same thing as clicking the element. So the checkboxes is hidden, but the label
is the toggle button. So when you click the toggle button, you are actually toggling the
checkbox and I'm using the state of the checkbox to display or hide the model. So for the model,
this is pretty useful. Well, you definitely want to control if your model is open or not.
If the model is maybe it's heavy, maybe it's loading extra stuff when it appears, maybe
for accessibility reasons, you don't want to render the content or something like that
when it's not actually on the screen. But if the model is something that it's, if you
don't kind of like don't care, if it's more of a visual thing of it being shown or hidden,
but it makes sense for the content to always be there, it's just like an extra information
or something like that, then maybe you can just leave it up to the view and that's fine.
It's kind of like using the, not the dialogue, but the how, I forgot the name of the accordion
element, like the native one where you can just like detail. So the detail open and closed
state, if you are using now, you don't control that as well. Right. So, so it's kind of the
same, but with the model, there are other elements that, that use that similar approach.
Well, one of the things that's the, sorry. Yeah.
Actually you didn't describe how you display the model depending on the state of the select.
Sure. Oh, I got the checkbox. Sorry. Yeah. So it's a, it's a CSS thing. I just use the
sibling checkbox with the actual model element. And I use that checkbox, checkbox checked
state to determine if the model is selected or not. I'm not only using Tailwind here.
I also have like this, this small CSS that I do more manual stuff. And one of them is
just using that model selection state to display the sibling model and make it like appear
with an animation, et cetera. One of the things that, that, that you lose, if you, if you
have like a model that only appears when you click something and it like it appears in
the DOM itself, just in that, that moment is it's really easy to animate the entry,
but the exit, you can't animate that unless you are keeping up like the, you are kind
of like tracking the state of the animation that those are all of those things.
There's always a good excuse of, Oh, well the user doesn't want to waste his time seeing
that model disappear. Right?
Exactly. So when you're only the DOM there, you can actually like do pretty easily that
fade out state.
Yeah. Nice.
Yeah. And well, yeah, I, I, I feel like Elm widgets and maybe my libraries as a whole,
they have a philosophy that is slightly different from one that is really common in Elm applications,
which is I try to make it easy for you to do the right thing. But if you want to do
something different, I prefer that you have the freedom and not try to lock you into the
perfect, the perfect state, you know? So for the model one, there is like the toggleable
model that follows this strategy that I just said to you. But there is also like the, the
usual model that, that we'll just like display and you can like track the state and you can
control if it's open or not. You can just like, I dunno, show it like at once when it's
rendered in the DOM and that's it.
And does that one also use the CSS trickery?
No, actually no. If you're not using the toggleable model, you, you not get the whole like hidden
checkbox and et cetera, because then you, you don't want people to, to be able to like
close it in any way other than like receiving the, the Boolean of is it open or not. Right?
Yeah. Something I noticed and we've also, we already talked about this. If you use that
toggleable or toggle button plus model, meaning you don't have any state for your model, then
you can't test that the model shows up in an Elm test because you're relying on the
web platform and we don't have any tools except end to end tests like Cypress or Playwright
to simulate that. We can't do that with Elm tests or with Elm program tests. So that's
Yeah. I'll just say that like, this is probably going to be true for anything that is done.
Maybe I don't know, like I don't know if just done, but like done plus CSS. Yeah. Scoped
right. Because like if you are using like, like Dillon said, like the detail thing, you
are also not owning that state of it. Is it open or not? So maybe you should use that
when you kind of like don't care. But yeah, if you want to control the flow, you better
use the one that you actually control the state.
I was also wondering, usually at least on the product that I work on at work, we have
our dialogues, they all have a close button in the corner and they also need to respond
to the escape key if you want to. If you press the escape key, then it closes. Can you do
that with the toggle button?
Sadly, sadly no.
Okay. Yeah.
Sadly, no. I don't know, like the ideal world, it would be if instead of using like, I don't
know, like regular HTML, we were actually using the new dialogue, like HTML dialogue,
because that actually gives you everything that you need to, to like, well, control those
states that the accessibility is handled by the browser. And hopefully widgets can evolve
into using those things as they become more available. But I don't remember.
Why are they not?
Why are they not using the dialogue?
Yeah. So, so I don't remember the exact reason, but the thing is that like dialogue right
now, it's sadly not as declarative as it, as it should be. You need to JavaScript to
be able to, to like display it in a way that actually it handles all of the events in the
way that you were expecting. If you're, if you're showing the dialogue, I'm not, I can't
describe you exactly what happens, but if I feel like there is a way that you can show
a dialogue in a declarative way, but then it kind of like, it, it, it doesn't work the
same as it would. I believe that it will, it will not respond to like this escapes things
and maybe it won't focus trap your, your inputs as well. All of the, so I don't know. I hope
that our widgets can like evolve, like keeping an eye on all of these like dumb possibilities
and just like use it more and more.
I'm guessing that you would then wait for multiple browsers to support that or you would
add a warning saying, don't use this if you don't support this version of this browser.
Sure. Yeah. Yeah. I'll just go and say that most, if not all of widgets is built using
like really established like browser APIs. So I'm not doing any like experimental stuff.
Right. So do you have any other fun CSS trickery in your bag and in Elm widgets?
Sure. Well, I feel like the pop over element is something that is also kind of tricky to
do sometimes and pop over and to tip are things that are like you could use just like a title
attribute instead of a two tip. But sometimes you don't want to do that. You want to control
like how it displays. You want to control, like you want to play some, some at like HML
thing there you want to, I don't know. And pop over it, it gets a lot harder, right?
Like pop overs. I don't know if you, if it's everyone knows what's a pop over because like
the, the way that you like the naming, it's, it's a bit different all of the time, but
it's like sometimes people call it just drop down or something like that. But it's the
element that pops up once you either hover or click another element. Right. So for, we
are using this, this idea of not just like hovering using CMS, but just like also using
the focus within a selector. So for the pop over one it shows up once you focus on the
element that you are using as the anchor and it gets positioned related to that element.
But then again, it also keeps appearing if you're interacting with the displayed element.
So it's sometimes it's a bit tricky to just like do that because I don't know, you're
interacting with the, the, the, the anchor thing. And then once you get outside of the
anchor thing, you lose focus, you lose the, the, the thing that you were trying to interact.
I don't know. So it's, it's another thing that it's really useful to just do it and
just like add a drop down menu or something like that. And not worry about like plugging
the messages to do that. I feel like this is another thing that can be frustrating for
beginners to, I don't know, like it should be so easy to do this. Why is it hard? Like,
you know, and this frustration it's, it's not that productive, you know? So if you want
to do that in a more controlled way, that's fine. Like the Elm it's exactly for that.
But I just wanted to, to give the like beginners, especially a more frictionless experience
at first, and then you can like evolve and control wherever you want.
Yeah. Are there trade-offs there with, cause like tooltips are notoriously difficult to
do only using CSS. For example, like if a tooltip is only using CSS, can you know if
it's going out of the bounds of the screen? I actually wonder if some of the new like
has selectors or things like that could allow for something like that in pure CSS that wasn't
possible before. But as far as I know with traditional CSS, you can't do that.
Yeah. Well, definitely not in a stateless way because yeah, I would need to kind of
get bounding, like the bounding box, et cetera. But, but no, like the way that I'm doing right
now, it's more, it's more simple. Like it's more focusing on like, do you know where this
will show up? Like it's easier for you to just say to me like, okay, position this to
the left side or to the right side, et cetera.
Right. So something is at the very top of the screen, then you're going to say, put
it on the bottom and.
Yeah, exactly. Yeah.
Okay, cool. Yeah.
Those things here that like rely on relative positioning can get a bit tricky because those
are one of the things that, that might get screwed up if you, if you are using a non-standard
parent styling, you know? So if you are placing an element that is using kind of like this,
this popover thing, now I have to, to have this wrapper of that element. And then if
you want to style the anchor itself and not the disparate element that I've included in
the DOM, then you're kind of stuck. I don't know, like so there are a few places where
sadly I, at least so far, I couldn't find a way for me to bypass like this DOM restrictions,
you know?
I'll be very curious to see what, what kinds of like CSS wizardry become possible for kind
of this stateless Elm philosophy with, with the has and is selectors in CSS. Because yeah,
like I'm, I'm also a big fan of this approach of like, like for example, a hamburger menu
that you, you just have a global menu and it's visible or hidden based on a click on
mobile, for example, then like, it's really nice to just not have to manage that state
in Elm. And even to be able to share code between internal projects at a company or
in an Elm package that just is, here's the CSS, here's the view code, put it in there
and it just does the right thing because it uses a checkbox for the, for the visible state
because you don't really, it's a, it's a DOM concern that state and you really, you don't
care. You don't, you don't need that in the time traveling debugger to be able to go back
and track certain weird view states you get into. It's just you, you manage your state.
I don't care.
Yeah. Like maybe someone could argue that, Oh, I need to be able to debug that state
as well. And, and if you're doing something that's really complex, I would get that. But
I feel like there's a trade off there, right? Like there is some complexity line that we
want to cross before getting into the whole state management thing. And I don't know,
it's fun to think about Elm widgets being this repository of, of strategies for doing
all of that. After using, starting to work on Elm widgets, I started to, to just, I don't
know, you just search, right? Like how can you do this with pure HTML and CSS? And there
are like tons of knowledge out there of people already doing that, those things. And it's
just like really spread apart, like in Stack Overflow and this like weird tutorial that
it's hidden in a block somewhere. And if we can just like place everything in the same
place might be fun. And I feel like it's especially useful for Elm applications since for us dealing
with all of this plumbing sometimes gets painful.
Yeah. I know that this might go against your philosophy of like simple low boiler plate
wiring, but have you thought at all about bundling certain things with web components
where, you know, this kind of power where you can put the state into some internal thing
that Elm doesn't have to care about that can be really declarative. Sometimes web components
can be a really nice way to abstract that. But of course you then need to include JavaScript
code in order for those web components to be renderable from your Elm code.
Sure. Yeah. Like I love web components and like at work we use them. So these strategies
definitely something that I, I vouch for. At the same time, I feel like it's similar
to the Elm select thing that I mentioned. Like it's, it's good for us to define that
we won't have that in Elm widgets, but at the same time, if there are some like really
useful tools, maybe we could point them out. Like, okay, if you want to do this, like,
I don't know. One of the things that is not really a like element, it's like, it's not
really a UI element itself, but it's super common. It's how to, to deal with like translations
and like, because it's still like a way of, of you handling texts. Right. And there's
tons of different strategies. There is like, I won't go into all of them here in any way,
but at the same time, knowing that web components is a particularly useful one might be helpful.
Right. So if you're looking for an element and there's like, okay, internationalization
or something like that, maybe we can point out to some packages that are more focused
on stateless UI, but it's still a stateless UI that is aimed towards that goal. I don't
know, because thinking about another, like really good stateless, stateless package,
stateless UI package in the Elm repository, Teresa's Elm charts, right? There is no state
there, but maybe there could be like a lot of optimizations if there was state, because
there's like a lot of work going on in each render, but at the same time, like it makes
the API so good. It's so simple to just like copy and paste some code and that's it. There's
no boilerplate. And if you think about it, the stateful parts, because there is state
actually, sorry. But if you are using like the two tips and those things, then there's
state, because like it gets handwritten like in the proper places, et cetera. But it's
by far the most difficult part of Elm charts. Like if you want to use events and just like
figure out how things line up together, it's the place where people get kind of like, they
get trapped. One thing that Jeroen mentioned to me a while back is that you said, Jeroen,
that, oh, I thought that Elm was not able to work with CSS variables.
Yeah. I was going to ask that about that.
So this is one thing that, I don't know, all of these things that are kind of like living
in the gray area between Elm and the DOM, I sometimes fear that I'm kind of like using
a skate hatch in some way, something that might get fixed in the future or something
like that. CSS variables, I hope that's not the case because like the Elm, I feel like
Elm style, it does some sort of parsing of what you're giving it. Because I actually,
I was able to declaratively call messages from the DOM using some hacks.
Using the style function?
Not the style, but I actually got, I was able to do that using the image tag because the
image tag, if you throw it in the DOM and it doesn't load properly, it throws an error
event. So you can just like use the image, like a non-existing image and bind the error
event to whatever you want. And since it can be like a hidden image or something like that,
you can declaratively call messages from the DOM. I'm not using that. I'm just saying that
those things are available. But if you use that, you are treading dangerous paths. But
for the CSS variables, I discovered that Elm disregards a few style keys. So if you're
using a style or values, I don't know, but it kind of like tries to validate it and it
just like ignores if you do something wrong. This can be frustrating. And I believe that
style, you can only place one style in the element. Maybe I'm saying something wrong
here, but there is like also the, sometimes if you are using a style and you like place
another style, it only uses the last one, right? Because it's not like a class that
concatenates all values. Like for styles, I believe that it's just like, it's just using
the last. But if you are using the, well, first it should be valid to use CSS variables
in like anywhere that you are using CSS values. I feel like this is just like something that
Elm is wrongfully validating against. But to bypass that, I'm just using the node attribute,
like the attribute function directly, then it bypasses that and it can use CSS variables.
Oh, cool. Yeah. So there is no, there is no like hidden image with like a hidden on error.
Yeah. I was going to say that would definitely put you on Santa's naughty list for this year.
Good thing you didn't.
So the issue with CSS variables is, is only the fact that Elm sometimes ignores them,
Yes. Yeah. At least from what I could tell. And it's not all the time, like for a few
styles it accepts them, but for other ones, like it doesn't, I don't know.
And so if I'm understanding correctly, the main purpose of CSS variables for this tool
is that low boilerplate goal of being able to basically say, here's my theme, here's
the base CSS, and then you just use widgets and it pieces them together and you don't
have to wire through your theme and base styles everywhere. You just declare it up front and
then it using CSS variables, it's able to basically, you declare your theme, it sets
some CSS variables, you declare the base style, it's referencing those CSS variables, and
then you use your widgets and it's using those styles with the CSS variables.
Yeah. But not only that, and here I'm going to do the pitch for Elm team itself, because
like it's pretty useful even if you're not using widgets. The whole idea of Elm team
is first, the team itself is this constraint based declaration of like, there are this
five colors. I spent a lot of time just trying to do the minimum necessary, like amount of
colors and variations of colors to give you flexibility at the same time that gives you
like constraints. And the thing is that Elm team is not only declaring that, but it's
also creating team scopes in your application. For instance, in a website, sometimes like
a marketing website, it's really useful to have the same section. You might use it in
a white background and then you want to create some visual diversity and you want to use
a dark background later. And you want to change what is the primary color depending on which
is the background itself. So you can actually create a number of teams and use them in the
same page. So you're not restricted to using like one team per page in any way. So we use
that for our website. So each section, we have like, I don't know, like five different
teams because our company uses gray as the main background color. So we have like five
lightness of gray, like a gray, how do I say that? Shades of gray. And we can just like
mix and match whatever you want. And if someone, okay, so this one here should be actually
a bit darker and we can just like change this one team variable and that's it. So Elm teams
handle that. But not only that, it also handles dark team. Like if you want to declare for
each one of those scopes, different teams for different dark modes, you can. And once
you go to the dark mode, every single team container will change. So it's super flexible.
So even in our main application, we have like two or three kind of like similar teams, but
maybe we want to give this element a highlight and it's using the same kinds of like components
inside, but we give it like a slightly different team and that's it. Everything still fits
together. We can decide into changing what team we want based on any kind of like variables
and play that. And that's it. So Elm team gives you all of that. And CSS variables are
an ideal way of doing that, right? So all of the elements styles are only using the
same values and we are just like providing these scopes that will change the actual values
that you are using. That's it.
That sounds very nice. I think it'd be the same thing in React at some point with providers.
Is that?
Providers? Yeah. There are a few teaming libraries in React that you can, well, not just React.
Flutter uses the same thing where you can kind of override the provider that you are
consuming. So you can have like a global provider and then like in your handler tree, you can
have another provider that kind of like overrides the previous one or just changes a value.
It's really useful for teaming as a whole.
So you mentioned that you selected a number of properties of the theme or a number of
things that you could set up so that you're constrained. So I'm looking at the package
right now. So for instance, you can set a theme color for primary, for secondary, for
success, warning, danger, right? Maybe you can't do it for tertiary or another one. So
you're very limited in what you can do. And I found that to be a bit scary, actually.
But you say that you did that on purpose. So I would love to hear more about that.
Sure. Since Elm theme aims to be used in the same page, like with multiple themes, then
you can get around that having multiple themes having like slightly different colors if you
want. But at the same time, the thing that is most difficult is not actually deciding
the number of base colors. Like for instance, we have like a base, a neutral, primary, secondary,
and then the status ones like success, warning, and danger. But the thing that is really difficult
is actually defining these three variations of the same color, which I decided on background,
foreground, and auxiliary. And the thing is that I want to be able to use some colors
as a foreground of the main background. Sometimes I want to use a color to be like a button.
Sometimes I want the color to be used in an icon that is like overlaying another color.
And this can get quite difficult, right? So if we have like this matrix of possibilities,
it's still, I don't know, possible to not go crazy and make sure that everything's working
So if you go to the Elm widgets, Elm book, in the theme page, there is a theme generator.
I'm going to make that more useful so that you can like just throw your own theme there
and you can export the theme there that you are using. But it's pretty simple to see how
you can just like slightly change a color and see how it breaks compatibility with everything
else. Like, okay, so I'm changing this color, so I'm breaking contrast with all of these
other possible matches.
But once you have everything lined up and everything is accessible, then you are making
sure that all of your components that are following these same combinations, they are
also accessible. So I know that my button can be like a success button with like a success
background and a success auxiliary color as a foreground. I know that I have like a auxiliary
base color as the kind of like light color of text on the main background. It can get
a bit hard to talk about in like in a podcast like this. But it's not that complex when
you are seeing it. And I don't know, I feel like, how can I say this? When building a
design system, it can get a bit hard to talk about themes.
People are used to talk about defining or color palette. But once you talk about themes,
you're not talking about the color palette itself, you're talking about the color variable
palette. You are creating a layer of abstraction between your actual color value and the thing
that you are using on your code. So it can get tricky for designers to actually think
about a component in a way that is not specifically tied to a color, but it is tied to a color
So when I'm creating a button, I'm not thinking about, I'm going to use the color red here
and this like white on top of it. No, I'm using this background color because semantically,
it's what makes sense. And I'm using this foreground color on top of it. And I don't
care what it is. It's kind of like I'm always working on grayscale and everything is still
visible. But if someone wants to change all of the colors, that's fine because we are
talking about the contract is in this layer in between this abstraction layer of the team
And I feel like this is not the common place yet. I forgot the name of the thing, but there
is this JS styling framework that is getting a bit of a buzz right now. I'll try to remember
the name and I'll send you so you can add it to the show notes or something like that.
Put it in the show notes.
But it does exactly that. The whole thing is that it creates this team layer where people
can just define different teams and everything will look, it will work in all the teams.
And just by doing that, people are kind of like, oh, this is really great, et cetera.
So yeah, it's not that common.
Yeah. Well, great. Jorge, where should we point people if they want to follow you or
get started with Elm theme and Elm widgets?
Sure. I'm Jorge Borges in every single like, I don't know, like Twitter, Elm Slack, discourse
and everything basically. So you can find me there, please. And for Elm widgets, it's
on the Elm packages as Elm widgets, uncover slash CO Elm widgets. And there is also the
Elm book that you can find through the docs, but it's called Elm slash widgets dot netlify
dot app. And there you can just like have a run through of the different components
and how you would set up. I plan to really evolve it bit by bit. I'm kind of like hoping
this is not my Dwarf Fortress project, you know, like something that I'm working on for
20 years.
There is nothing wrong with that.
Trigger warning.
But, but, but yeah, like I, maybe this can be a, I really hope that this, this becomes
more of a community thing than Elm book. Like Elm book, I'm super grateful because there's,
there's a lot of issues open right now, which I'm excited about because most of the issues
are not actually bugs, it's just like people asking about stuff. And I hoped for Elm widgets
since it's more of a well-scoped set of things, like each module it's, it lives in isolation
from the others. So I hope that people can be more like contributors, like in the code
itself, right? Like just go there and make your CSS trickery available to the whole Elm
community. Yeah.
Cool. Amazing. Well, thanks again, George, for, for coming back on. It was a pleasure
to have you again.
It's always a pleasure. And I hope to one day open this podcast with, hello, Jeroen.
And Jeroen, until next time.
Until next time.