Thinking of web applications in terms of state machines is not a new idea; in fact, it has become so popular in the past few years that teams are spending increasingly more time breaking down their application into states managed by front-end frameworks.
Whether you use Redux, MobX, or even perhaps something framework-agnostic like xState, it is clear that thinking about web applications in terms of state machines is occurring much more frequently.
With all this focus on state, transitions, and the benefits that come with structuring our applications like this, I’ve found there is still an area that is often overlooked when it comes to managing state in web applications: the visual or presentation layer.
CSS is incredibly powerful yet frequently misunderstood by most developers, which often leads to derision of the language.
I think this is mostly due to a fundamental error in the way web developers manage presentation, often focusing their efforts on conditional logic in templates instead of a more flexible application of state-specific CSS selectors to HTML elements.
A simple example
Let us examine a simple example of a multi-selectable list for a user interface (UI) that a designer may have provided in mockup form for us as web developers to decompose into working code.
We can see there are a number of interactions at play, and at first glance these might seem simple enough that we would be tempted to solve the problem without putting much upfront thought into it. However, I think despite the simplicity of the example, there are enough complex states to enumerate that we should spend some time thinking about them before we dive into creating this UI.
Putting aside interaction design (IxD) and accessibility (a11y) concerns for the time being, after enumerating the states that we see here there is a lot to consider when building this UI! How should we manage the states? Should the logic live in our template or in our stylesheets? Let’s take a brief look at the first approach, using an implementation in Svelte.
Svelte is a compiler that takes as input one or more .svelte
files with regions of functionality based on JavaScript, HTML, and CSS; with that input it produces the minimal amount of DOM API output in JavaScript to achieve the desired result. It’s a different take than something like React, Angular, or Ember, which ship substantial runtimes to the browser that execute application code.
If you are interested in learning more, I highly recommend watching this excellent talk called Rethinking Reactivity from Rich Harris introducing some of the core ideas. The code in the following examples is intended to be simple enough that you should be able to port the ideas represented to any other framework with minimal effort.
Implementation: Templates
One of the first places a web developer might start is by crafting the template that represents the UI mockup we received from our designer friend above. This seems like a logical place to start, given we need some way to represent the data in a web browser. Let’s build a template using svelte-infused HTML and see how it looks.
<table>
{#each users as user}
<tr>
<td class="icon">
{#if user.selected && hasSelection}
{checkedBox}
{:else if !user.selected && hasSelection}
{uncheckedBox}
{:else}
{snowman}
{/if}
</td>
<td>
{user.name}
</td>
<td>
{user.email}
</td>
</tr>
{/each}
</table>
Aside from the svelte-specific things like the {#each}
and {#if}
blocks, this is probably close to what you might implement in any front-end or server-side templating solution. We’ve taken the list of potential states that we extracted from the mockup above and encoded them as conditional logic in our templates in order to achieve the desired result. The one special case we needed to account for was the non-interactive state “1 or more Selections Active”; to do this we defined a local variable in our JavaScript region called hasSelection
which is defined using Sveltes reactive declarations as $: hasSelection = users.some(u => u.selected)
.
Although the code above satisfies most of the user experience (UX) as detailed in the mockup, there are two problems that shake out of an implementation like this that focuses on conditional logic in templates:
- We didn’t capture all of the states enumerated, as we cannot effectively translate a user’s
hover
action in templates alone unless we get really creative and complex - This paradigm scales very poorly as our templates grow, mixing concerns of
presentation
anddata
in a template, resulting in code that is much harder to read and maintain over the life of a project
The scalability concern is the more worrisome of the two, yet is a common byproduct of developers using conditional logic in templates. Increasingly thorny conditionals can lead to missed acceptance criteria, which in turn can lead to stress and tension on a team. Rather than throw blame around, it’s worth focusing on whether that approach is healthy for a long-term project.
I think we can do better if we shift our focus from conditional logic in templates to thinking more in terms of leveraging CSS as the language we use to define the states in our presentational state machine and using JavaScript to manage when to apply those states. Let’s see what that looks like as we refactor the above example.
Implementation: Stylesheets
One of the first considerations we’ll need to make is how to address both the concerns raised in the previous section. We need to handle the hover
state properly, and we also should strive for a solution that encodes data in the template and presentation in the stylesheets. Let’s start by refactoring the template to eliminate the conditional logic:
<table class:hasSelection="{hasSelection}" class="selectable">
{#each users as user}
<tr class:selected="{user.selected}">
<td class="icon"></td>
<td>{user.name}</td>
<td>{user.email}</td>
</tr>
{/each}
</table>
The first thing you might notice is that we removed the conditional blocks replaced them with svelte’s class element directive. This is an elegant way to control toggling of a CSS class on an element via a boolean value, which we previously defined as {user.selected}
and {hasSelection}
. We also added a class=selectable
to the root table element in order to allow us to better manage the complexity of the conditional logic for states in CSS. Let’s defer looking at the JavaScript that defines those values and instead look at what the definition of each state in our presentational state machine looks like when we encode it with CSS:
/*
CSS variables in conjunction with escaped unicode or html
entities are a great way to represent things like icons
*/
:root {
--unchecked-box: "\02610";
--checked-box: "\02611";
--snowman: "\02603";
}
/*
Managing the hover states to show a yellow background
*/
tr:hover,
tr:hover td {
cursor: pointer;
background-color: yellow;
}
/*
Our first state, every icon should default to the snowman
*/
.icon:after {
content: var(--snowman);
}
/*
A complex state, if the table has a selection,
then every selected items icon should be the checked box
*/
.selectable.hasSelection .selected .icon:after {
content: var(--checked-box);
}
/*
A combined selector to handle the alternative complex states:
- for a table without a selection, when the user hovers, show the unchecked box
- for a table with selections, swap the icon from the snowman to the unchecked box
*/
.selectable:not(.hasSelection) tr:hover .icon:after,
.selectable.hasSelection .icon:after {
content: var(--unchecked-box);
}
With the combination of CSS and svelte-infused HTML we’ve achieved the result our designer was hoping for when they handed us the initial mockup, with an appropriate separation between the definition of our states (CSS) and the application of those states (HTML, and JavaScript).
For completeness, here is the entirety of the example as included in Application.svelte
from the code on github:
<script>
let users = [
{ name: 'Danika Dywtgowm', email: 'danika.dywtgowm@email.com' },
{ name: 'Erica Bule', email: 'erica.bule@email.com' },
{ name: 'Jim Snales', email: 'jim.snales@email.com' },
{ name: 'Daria Thorobox', email: 'daria.thorobox@email.com' },
{ name: 'Mendikant Hargrove', email: 'mendikant.hargrove@email.com' },
{ name: 'Ephraim Lischok', email: 'ephraim.lischok@email.com' },
{ name: 'Lera Nedialkova', email: 'lera.nedialkova@email.com' },
]
function selectUser(user) {
users[users.findIndex(u => u.name === user.name)] = {
...user,
selected: !user.selected
}
console.log(`${user.name} was ${user.selected ? 'de-selected' : 'selected'}`);
}
$: hasSelection = users.some(u => u.selected)
</script>
<style>
:root {
--unchecked-box: '\02610';
--checked-box: '\02611';
--snowman: '\02603';
}
td {
padding: 5px;
}
tr:hover,
tr:hover td {
cursor: pointer;
background-color: yellow;
}
.icon,
.template-icon {
display: flex;
justify-content: center;
}
.icon:after {
content: var(--snowman);
}
.selectable.hasSelection .selected .icon:after {
content: var(--checked-box);
}
.selectable:not(.hasSelection) tr:hover .icon:after,
.selectable.hasSelection .icon:after {
content: var(--unchecked-box);
}
</style>
<h1>Complex Multi-Select</h1>
<table cellspacing=0 class:hasSelection={hasSelection} class=selectable>
{#each users as user}
<tr class:selected={user.selected} on:click={()=> selectUser(user)}>
<td class=icon height=20 width=20></td>
<td>
{user.name}
</td>
<td>
{user.email}
</td>
</tr>
{/each}
</table>
Closing thoughts
This is how I have tended to manage the working relationship between HTML and CSS for the last 20 years, and I think the power of thinking in this way leads to cleaner code and easier to refactor web interfaces.
If this looks completely foreign to you and you found yourself considering that the template-based conditional-logic approach made more sense, I’d recommend learning more about the capabilities of CSS features like pseudo-selectors :not, variables, and the generated content: property.
I’ve found that teams who up their level of knowledge in CSS and tend to try to split concerns like we’ve done here will have web applications that are easier to change over the long term.
If you are interested in learning more about this approach and seeing a live coded version of this blog post, please check out the screencast posted to my YouTube channel; it walks through all the examples and touches on a few more svelte-specific things to consider.
Learning resources
- Svelte Tutorial
- Complex-Multi-Select Code on Github
- CSS Variables
- CSS :not pseudo-selector
- CSS Generated Content
- HTML Entity Symbols
Transcript of the talk
[00:00:00] Hey, it's Dave from Test Double. Thinking of web applications in terms of state machines is not a new idea. In fact, it's become increasingly more popular in the past few years that teams are spending significant amounts of time breaking down their application into states managed by front end frameworks.
[00:00:20] Whether you use something like Redux, MobX, or maybe even something framework agnostic like XState, it's clear that thinking about Our web applications in terms of these state machines is occurring much more frequently. With all this focus on state transitions and the benefits that come with structuring our applications like this, I found there's still an area that is often overlooked.
[00:00:41] The visual or presentation layer. CSS is incredibly powerful, yet frequently misunderstood by most developers, which often leads to derision of the language. I think this is mostly due to a fundamental error in the way that web developers manage presentation, often focusing their efforts on conditional logic and templates, instead of a more flexible application of state specific CSS selectors to HTML elements.
[00:01:06] In this screencast, we're going to take a look at a simple example UI, a multi selectable list of users that a designer might have provided in mock up form for us as web developers to decompose. Now, if you prefer to learn by reading, please check out the full article linked in the video description below.
[00:01:22] Otherwise, let's get started. All right, let's dive in here. So, we're talking about CSS as the visual state machine, and I mentioned before in the introduction that there was a simple UI that we were going to recreate. Let's take a look at the example here in this animated GIF. So we can see that there's a number of interactions at play, and at first glance these might seem simple enough that, uh, we would be tempted to solve the problem without putting much up front thought into it.
[00:01:47] However, I think despite the simplicity of this example, there's probably enough complex states here, uh, to enumerate that we should spend some time thinking about them before we dive into creating this UI. Especially considering we were talking about state machines, and thinking of our the presentation of our application in terms of states.
[00:02:05] So we've got a selected state where we can see that a user can click, and then the icon turns into a checkbox. We've got an unselected state where the icon becomes an empty checkbox. We have a hover state with no selections, where the snowman icon shows up for the hovered row. And the hovered row also changes to an empty checkbox, just as a way to give a user a hint that they're Is a potential for them to, to select an item.
[00:02:32] Then we have hovering with one or more selections, uh, where all the unselected row icons remain as empty check boxes and the yellow highlight appears on the hover row. And then we also have a sort of a derived state, which is one or more selections that are active. And in that case, all the icons change to empty check boxes to indicate the ability to select multiple rows.
[00:02:53] So we could think about interaction design, we could think about accessibility concerns, uh, but I think we're going to put those aside for now and just think about the states that we've enumerated and how to build this UI. And this is a good question, how should we manage these states? Should the logic live in our template or in our stylesheets?
[00:03:09] And I think that's ultimately the conundrum that a lot of developers get into when they start, uh, thinking in terms of decomposing complex states into their UI. And so we're going to take a look at, uh, the first approach, which is working with conditional logic and templates, and we're going to use something called Svelte.
[00:03:25] And if you aren't familiar with Svelte, it's a compiler that takes as input one or more Svelte files with sort of regions of functionality based on JavaScript, HTML, and CSS. If you're familiar with Vue, and you've used that before, uh, you'll feel right at home. Uh, Vue has a vue file, Svelte has a svelte file.
[00:03:43] And it's a little bit of a different take than something like React or Ember or Angular, but as we'll see, um, there are pieces that overlap in functionality. And, uh, the, the other main difference is that Svelte, um, doesn't ship its runtime to the browser. Uh, and if you're interested in learning more about that, we're not going to cover that in this screencast.
[00:04:05] I would definitely recommend watching, uh, this excellent talk called Rethinking Reactivity. You can either check out all of the, uh, resources listed at the bottom of this post, or you can check out the video linked in the description below. But, uh, Rich Harris, the creator of Svelte, has some really cool ideas, uh, that talk about why Svelte was created.
[00:04:24] So you can check out Svelte at svelte. dev And, uh, the tutorial is a great place to start. So if you are just wondering what, uh, Svelte is all about and how to get into it, I'd recommend starting there. But for now, uh, we're going to stop with the, uh, sort of dictation from the blog and we'll jump into our first implementation.
[00:04:45] So I have a basic project, uh, set up here and to start, there's a script called dev. Uh, Svelte comes with rollup as its. Package. dependency manager tool slash bundler. Um, and so, uh, you can scaffold out a project. There's a template you can get. You can check all that out in the Svelte tutorial. We're going to start with our app.
[00:05:10] svelte file. And we're going to start with our list of users. And so the idea is thinking about that UI that we got from our We want to decompose this into, um, some representation on the screen. And again, I mentioned before, Svelte has regions of functionality. So a svelte file consists of a script block, where all of our behavior as JavaScript goes, a style block, where our style sheets can go, and then just HTML.
[00:05:36] Um, if you're familiar with Vue, you might, uh, be Thinking, why didn't they have a template, uh, directive? They just don't, in Svelte, anything that comes outside of the style or script will automatically try to be rendered into the root of the component, um, as a template. So let's think about getting our list of users on the screen first, and we're going to do it with a table, because I think a table, um, makes the most sense.
[00:05:59] So let's just try and get our list of users on the screen to start. So in, uh, Svelte, we have iterators. We can do each users as user. And the cool thing is, all of the template context, um, so the fact that I can see users inside of here, Svelte auto wires all that stuff up. And again, it can do that because it's a compiler.
[00:06:22] Uh, and the, the value that's emitted in the bundle file is literally just DOM directives. And we might take a look a little bit at that later. So let's get our users onto the screen. So we want a table row for each user.
[00:06:38] And within there we can see that our users have a name and an email. So let's put those in just as placeholders. We use single curlies in Svelte, which is similar to other languages. Let's get that up and running here. I think that's on 5000. There we go. And we'll just make things bigger so that we can kind of see.
[00:07:00] Uh, the default Svelte configuration has live reload. So as we go changing this, uh, we'll be able to see what happens. So there's our list of users. Not too exciting. So we need to think about how to model, uh, the complexity of those states that we're working with. Um, and we, and we also need to model the icon that showed up in that, uh, that animated GIF.
[00:07:19] So let's think about where to put the icon. Uh, we're going to do that here. In another table data tag. Let's give it a class of template icon. Let's give it some properties of height and width. Just so that when we hover they aren't going to jump around. And this is where we start thinking about, um, selection.
[00:07:39] So we need some way to flag our users as selected. I like to start in the template often because I think that's where most developers start. And so if we add a conditional here that says if the user that we are currently iterating over is selected, um, then we can render the checkbox. So let's do that.
[00:08:02] And this HTML, uh, directive in Svelte tells it to, um, unescape the value so that it doesn't, uh, put the HTML entities in place. The other condition we have, um, is if the user isn't selected, then, uh, we want some HTML with the unchecked box.
[00:08:31] And then we also have another else condition, uh, to account for, for the snowman.
[00:08:40] And these conditions aren't quite as straightforward. As truthful as we need, we also need, uh, to determine, uh, the state where overall there's a selection, uh, so that we can alternate between showing a single checked box or all of the checked boxes. Uh, so we'll do that with a Boolean that we're going to create called hasSelection.
[00:08:57] And that also modifies this condition. So let's read through it. If the user is selected and we have a selection, we're going to show that checked box. Otherwise, if the user isn't selected but we do have a selection, we're going to flip all of the icons to an unchecked box. And the final condition is just the default condition with the snowman.
[00:09:18] So obviously this isn't going to work, and we'll get a compile error, um, which is one of the benefits of Svelte, and so let's start adding the pieces that we need in our JavaScript. And we can do that up here with HTML entities. So we have a snowman, we have an unchecked box, and we have a checked box. And a great place to grab icons, uh, if you are interested, is this TopTal website that shows a bunch of HTML entities.
[00:09:50] And if we search for snowman, we can see we've got the Unicode, the Hexcode, code. So those are the values that I'm going to use. I'm going to use the HTML entities code, so I'll just grab that.
[00:10:03] And we'll paste it in there. And the unchecked box is ampersand pound nine seven four four. And the checked box is ampersand pound nine seven four five. So if we save that, now we still need to define our hasSelection. Thanks for watching. And the thing about, uh, hasSelection is it's going to be a computed property.
[00:10:31] Uh, and we define a computed property in Svelte using kind of a cryptic syntax, but it's essentially valid JavaScript using what's called a label. And so in Svelte, any reactive statement, uh, is prefixed with a dollar sign. So if we say hasSelection equals, uh, and we'll just use a function to say, are any of the users selected?
[00:10:54] And that'll get us back to compiling. So now we have our default state, we can see the snowman. Uh, but we don't have any way to trigger a selection. So let's build that part next in the JavaScript. So we're going to create a function called selectUser. And we are going to look at the users. And we want to find a given user in there.
[00:11:17] where the user that we're looking for's name matches the user's name that we passed in. Once we grab that, we can use the spread operator to create a new assignment. And the reason we need to use the spread operator is because internally, Svelte, uh, won't emit change tracking in its compiled output unless it detects the spread operator or some other way to, uh, manage creating a new object and assigning it to a value.
[00:11:43] Uh, and you can read a little bit more about that in the Svelte tutorial under the section on updating arrays and objects and reactivity. So with that in place, we're going to find the user that matches the name that we're in here. We're going to take the existing property so that we don't lose name and email.
[00:12:06] And then we're going to add a new property called selected. And it's just going to be the opposite of whether the user was selected. And because we don't have a value for that, which is undefined, it'll coerce it into a Boolean value of true or false. And just so we can see that working, let's add a log statement.
[00:12:21] So we're going to log out, uh, whether the user name was, and we want to determine if they're selected or deselected. Uh, so if they're selected, And we'll say the opposite, because we're going to be inverting it. And let's log that out. So now we need a way to trigger that, uh, when we click. We don't have any way to do that yet.
[00:12:43] So that click is going to go onto our table row. So let's do that. And we do that with these onclick directives. This will look very familiar to you if you've done any React. And we'll say, we'll pass in the user that we're referencing here. So, we can see that we've got a preliminary build of that. We've got our logging worked out.
[00:13:10] The icon states are being managed. They're kind of jumping around a little bit. We can fix that up with some CSS. And as we move forward towards the rest of the states, uh, we can control that. So, so, let's think about where we're at. We've kind of covered our bases with, uh, the selected state. So I can click on one of these, um, and I can see, uh, if I have one or more selections active, then all the other icons are flipping.
[00:13:34] So the, the conditional logic in the template changes. We don't have our hover states, which is sort of a failing of putting all our conditional logic into the template to manage these states. Uh, and so that's one piece that we're missing. But we do have selected, unselected, and then this one or more active selection state covered with the template.
[00:13:51] And I think that this is a pattern that lots of people use, right? They will encode presentational concerns into their template in order to achieve a result. And it does work, but the challenge being, uh, that as we scale up and build larger and larger templates in our application. There becomes this mix of concerns, of presentational logic in our templates, as well as, uh, data, uh, displaying the data.
[00:14:16] So, I don't think that scales very well as you grow an application in terms of size and complexity. So, let's refactor this. We'll leave our table based, uh, select in place, and we'll just kind of call it out here. I'll say this is a template managing presentation.
[00:14:37] And let's duplicate that, and we'll add another one, and we will call it where the CSS manages the presentation. So we're going to get rid of all of this conditional logic in our template, and we need a way with our style sheets to sort of transfer all of these states that are encoded in the conditional logic into a style sheet.
[00:14:59] And so I'm going to get rid of that class as well. Let's just call it icon here. And we're going to delete all of the contents of this. And this just becomes an empty TD. And let's just stick it up here for now. and comment it out so that we know where we need to go with our refactor. So our, our, uh, template down here still works, our template, and now we're going to refactor to our CSS.
[00:15:29] So similar to how we used the HTML entities encoded in JavaScript, we can do the same thing in CSS using CSS variables. So let's define some CSS variables, and the browser support for this is pretty good. So we're going to have unchecked box. And we're going to have checked box. And we're gonna have snowman.
[00:15:53] And the root selector, uh, you can define variables other places, but the root selector in this case is scoped, uh, because of Svelte's compilation to automatically generate randomized styles so that you don't get, uh, cascade bleeding in and affecting things. Um, or subsequently, if there was another component, like a child component contained within this, uh, app.
[00:16:13] svelte file, um, these styles would only affect, uh, the, the root level here. They wouldn't affect the, uh, the child component. Let's add some basic styling to our TD elements. We'll just give it a little bit of padding to space it out. Let's add our hover styles. That one's an easy one. So we want cursor pointer to let users know that this is an interactable thing.
[00:16:36] And then we want to put background color, uh, yellow so that we see the hover. So there we go. We've got that. We've got this funny gap between things. I think we can eliminate that by adding self spacing 0 on our table.
[00:16:54] There we go. Now we have a nice row selected. Let's port that over to our other template as well. They're still kind of jumping. We'll fix those in a sec. Okay, cool. So we have our basic hover state managed in CSS. So now let's think about how to encode these pieces into, uh, our styles. So let me paste that back in here.
[00:17:20] So let's start with the first one, and we'll say, uh, if the user's selected, let's have that be selected, and we're gonna select that icon, and we're gonna use a pseudo selector after, and we're gonna use generated content add the value of our variables, which we'll define in a sec. And so this is going to be content var snowman.
[00:17:47] And actually this is just going to be our default one of snowman. So any icon, uh, element within a class of icon, in this case the td, is going to have a content of var snowman. So let's put the snowman in there, encoded in a different way. And let's put the other ones in there. 02611, 02610. And this is going to have a compiler error, so let's just get rid of that for now.
[00:18:15] So there's our snowman showing up. And our selection is working still. But now we need to also encode the rest of those styles into the stylesheet. Let's put some default styles on the icon. So any icon and, and, uh, the template icon in our template managed presentation layer. Uh, we're gonna put a property of display flex on those and then we'll justify the content center and that should eliminate the jump that was happening when we selected those things.
[00:18:40] Yeah, there we go. Now we don't get that jump between the rows. Okay, cool. So we sorted out that. Now we need to finish the rest of those states to get the unchecked box and the checked box to work. So let's do that. So we're going to say that, uh, any selected will have a class of selected, and its icon is going to change to the checked box.
[00:19:06] And we're also going to need to have the hover state. Let's see if this one works for now. So it doesn't work because we're not triggering that class of selected. So we can do that using a class bind method. template directive in our spelt template. And let's do that on the tr. And because we have a boolean property, it becomes pretty easy.
[00:19:27] So the syntax for this is class colon selected and then equals user dot selected.
[00:19:35] And now we can see that works. But now, uh, when we have one selection, all the rest of the icons should default to, um, the empty checkbox, which we haven't covered yet. So let's encode that one in our stylesheet as well. And we can do that by adding a couple of classes, uh, to our root element as well. Let's add the class of hasSelection that we defined as hasSelection in our computed property here.
[00:20:05] And that way we have a styling hook to trigger, uh, the conditional property of whether we have a selection or not. So in this case, let's say hasSelection. selected. icon. after
[00:20:24] And let's add the rest of them as well. Let's put another class on our table thinking about perhaps we want to extend this and make this a generic component that we can apply to any, anything, uh, some selectable thing. So we're gonna add a class of selectable. I like to do this as a way to sort of, um.
[00:20:42] almost domain, specify the domain of the thing that I'm working with as a top level class. And it also gives us some flexibility since now we can say any selectable that has a selection. The selected icon after will be checked box and any selectable that does not have has selection. When we hover over the row, then the icon becomes The unchecked box.
[00:21:15] Let's see how that works. So now the hover is working. We can see there. But we need one more rule to also account for when we have a selection. Um, any selection at all. So now we can say selectable. hasSelection icon after. And we can combine it with that rule. And now we get all of the complex states decomposed.
[00:21:39] So we took one, two, three, four style rules to manage all of the different complex states that were previously listing in these blocks of conditional logic. But the advantage here is we've separated The, the, the management of the presentational side and encoded those states. If we think of our, our CSS and our H team on our JavaScript as a state machine, the CSS states, um, and the application of those via JavaScript is now managing the presentation.
[00:22:10] And our template just becomes a presenter of data, which I think is a better separation of concerns as we grow our application. Um, the, the visual presentational stuff goes into the style sheet and the template based stuff. goes into the template where it belongs. And so this is how I prefer to manage, um, my projects.
[00:22:30] uh, dealing with managing complex states when it comes to presentation. Encoding things in the style sheet as opposed to, uh, encoding them in, in the template. Just cause, yeah, like I said, it doesn't, it doesn't seem like this pattern scales well. You, and you get a, maybe you've been on a project before where you know, Uh, you jump into that one template and it's just this nested mess of presentation and data rendering concerns, and you just can't really tease it apart.
[00:22:54] And so I really feel like this is a better path forward. But I'm interested to know what you think. Do you think this is a better pattern? Do you think this is complicated? Do you think it's, it's weird? Um, let me know in the comments below and I'd love to chat with you or reach out on Twitter. Uh, and I hope you've enjoyed this screencast and learned a little bit about Svelte in the process.
[00:23:14] We'll dive into sort of more complicated features in Svelte in some follow up screencasts that I'll be producing in the next few weeks. So stay tuned for that. Thanks for watching.