Video Summary and Transcription
Scalable forms in Vue, approachable for all skill levels, with code reusability and best practices. Front-ends divided into websites and applications, with forms being highly interactive and logic-heavy. Form Components in Vue provide accessible markup, delightful validation, and customizable props. Using vModeling encourages code reuse and collaboration. FormKit offers a comprehensive solution to form problems, including structured data, unique form keys, and robust validation UX. It simplifies form creation, supports CMS-like experiences, and provides advanced features and TypeScript support.
1. Introduction to Scalable Forms in Vue
Scalable Forms in Vue. Scalability on the client side. Code reusability and size of organization as metrics. Vue 2 scalability issues. Extract and reuse components. Rubric for measuring scalability: code reuse and best practices. Approachable for all skill levels.
Hi, I'm UJSlive, and thank you so much for coming to my talk, Scalable Forms in Vue. Now scalability brings up a question right away. What is scalability? And generally when we think about scalability, we think about sort of back-end tools, right? From the server side, it might look like load balancers and horizontal versus vertical scaling. Perhaps the requests per second in a traditional web application might be the way that you think about scalability, horizontal versus vertical scaling, things like that.
But I want to talk about a different kind of scalability today. And that's on the client side. What does scalability mean in your client side code? In your Vue code, what does scalability mean? Well, it means things like code reusability and the size of your organization plays a role, how big of an organization can use your front-end code and developers per project might be a good key metric to sort of be able to measure your scalability. Does this front-end code work great for a team of five people? How about a team of 100 people? And this is one of the key drivers behind Vue 3. On a podcast recently, Evan Yu was quoted as saying Vue 2 has scalability issues. We have a huge Vue product and we have these huge components that nobody wants to touch anymore. We don't know how to extract and reuse things. Interesting.
So, let's use what Evan is saying. But first, real quick, who am I? My name is Justin Schrader. You can follow me on the socials at JPSchrader. And if you do happen to know me, it's probably from one of these open source tools that I have either created or am involved with, FormKit, Arrow.js, AutoAnimate, Tempo, and Drag'n'Drop. The last two, Tempo and Drag'n'Drop, are brand spanking new. If you haven't checked them out, you should totally go check them out. Tempo is sort of a Day.js or Date.fns alternative and Drag'n'Drop is a really easy to use little Drag'n'Drop library. But that's enough about me. Let's get back to what Evan was saying there. Scalable front-ends. Basically, I think if we distill down what Evan is saying about a scalable front-end and what we sort of know from our own intuition, we can come up with maybe like a rubric to measure scalability. First of all, I think it should enable code reuse, good code reuse. We all kind of know that this is something that is true. When you write code, you should be able to reuse it effectively and efficiently across your team, and that is part of what makes scalable code. Also, it should encourage best practices. Scalable front-ends should encourage best practices. Your code isn't very scalable if, in order to add accessibility, it requires a full rewrite. Also, it should be approachable for all skill levels.
2. Scalability and Skill Diversity
Scalability with diverse skill levels. Approachable for all developers. Tailwind's scalability due to standardized set of class names.
This is actually a really big deal when you think about it, especially with a large team. The bigger your team gets, the more likely it is that it's not just going to be a bunch of super senior front-end engineers. No, it's more likely that you have a big diversity of skill levels. Some people who are brand new and some people who maybe have been doing it for a long time. A good, scalable front-end should be able to work well for all of those people. Everybody should find it approachable.
And finally, is it conducive to a team of developers? This is sort of maybe a summation of what we're saying here. How many people can you put on front-ends in order to make them and still have them work efficiently? I think this is maybe one of the biggest drivers behind Tailwind being so successful, is the fact that anybody can step into Tailwind and you don't have to go relearn all of the class names that exist in an existing project. There could be thousands of them. You have a standardized set. Anybody can get in and make modifications. They know the modifications are limited to something local, so on and so forth. This talk's not about Tailwind, but it is to say, I think that's one of the reasons why you can make the claim that Tailwind is scalable.
3. Front-Ends: Websites and Applications
Front-ends divided into websites and applications. Websites are content-heavy with minimal interactivity. Applications are highly interactive and logic-heavy, making extensive use of forms. Plan A is to use the FormData API, but it has limitations.
Okay. So, let's look at front-ends. And roughly, we can divide them into two different categories, right? We've got things like websites, and then we've got things like applications. And websites are content-heavy. They're, you know, have minimal interactivity and limited business logic. So, you're thinking like, you know, a blog or something like that. Those are websites.
Applications, on the other hand, are sort of what are driving the internet. The commerce machines. They are the things that allow us to do something on the web. And they're highly interactive. They would have, you know, a lot of different ways to input information into them. They're logic-heavy. They're running entire business applications. We're thinking CRMs and CMSs. And basically, they make use of extensive forms. In fact, they make such heavy use of forms. You could really just call them forms. Yeah, technically, they're applications, but so much of what they do is the input and output of the information that is in that arbitrage happens in the medium of forms, web forms.
So, let's look a little bit more closely at these applications slash forms. How are we going to implement them? Well, plan A should always be to just use the FormData API, because that's what's built into the browser. So, you know, it uses the platform. It has native validation. It's 0 kilobytes of JavaScript, because you're not sending anything, you're not sending any JavaScript to the front end. And it works, you know, technically with any server. Unfortunately, everybody has a plan until they get punched in the mouth, according to Mike Tyson. And I think I'm going to agree with him, at least on this one. The reality is that the FormData API is not quite so clear cut. If we take a close look at it, we'll see that this idea that it uses the platform. Well, that's true.
4. Form Components and Platform Limitations
Platform limitations: no structured data, limited native validation, and requires JavaScript for interactivity. FormData API not ideal. Form Components offer accessible markup, delightful validation, non-native inputs, customizable props, and vModeling in Vue.
But the platform can't even structure basic data. So, we're going to have to add something to that. How about native validation? Well, yes, it does have native validation. But you're basically only talking about, you know, a handful of validation roles. Otherwise, you're going to have to ship some JavaScript to the front end too. 0 kilobytes of JavaScript, that's not even really realistic, because it has no interactivity without JavaScript. You can't even do something as basic as, you know, a autocomplete or a repeater or something like that without JavaScript. So, not very realistic. How about works with any server? That's actually not true either. There's not even a standard body parser. Your API already probably uses JSON, so now we're just adding additional complexity.
All right, plan B, what else are we going to do? Well, we're not going to use the FormData API. We're probably going to use Form Components and have it send structured JSON. Let's examine the Form Components thing a little bit, because I think this is where most of you have probably fallen in the past when creating your applications. Okay, Form Components are a great idea. They let us write forms and form inputs, for example, that have accessible markup. You could have really delightful validation instead of sort of that native janky UI that pops up. You could have nice inline validation rules delightfully styled. You can use non-native inputs, things like autocompletes and fancy dropdowns, date pickers, and so on and so forth. You can have props to customize. And of course, in the case of Vue, you even have the ability to use vModeling on your components. You can vModel directly on a component and get information in and out of there. So it might look something like this. Here's just a text input. I imagine almost every one of you has written one of these at some point. Here we're going to just define a model. This is the data that's going in and out. Again, we said we're going to vModel. So somebody using the text input could vModel on the text input. We've got the value here, and then we just use it on the input that's inside of there.
5. Using vModel and Reusing Components
vModeling enables code reuse and encourages best practices like accessibility. It is approachable for all skill levels and conducive to team collaboration. Reusing the text input component with multiple inputs is simple and effective.
So we're going to vModel that value. And look, we're doing some good accessibility things. We've got a for attribute on the label, which is linked up to the ID here. And we've got some nice conditional DOM elements inside of here. If there's some help text, then we're going to show the help text, and we even use aria-described-by to make sure that we have accessible comments in our help text. And then the way we actually use this in our application is pretty straightforward. We're going to import that component, and we're going to use it.
So here you can see we're defining our form data as just a big ref object. And here we're going to just vModel some property of that. Now if you look here, you can see we're adding a bunch of classes on it. So here's an outer class, an input class, label class, so on and so forth. And then we're passing any errors that we need through to it. Okay, so let's measure this by our rubric here. Does it enable code reuse? Of course it does. Does it encourage best practices? Yeah, you saw we had accessibility going on there, right? That's good. It's encouraging best practices. Is it approachable for all skill levels? I think using the text input is not too bad. Is it conducive to a team of developers? Sure.
Okay, well, let's try to reuse our text input and see how it handles this. It says it enables code reuse. We'll just try to reuse it and see how it works. So here's our text input. And you can see that it's got a bunch of classes. We don't want to get rid of those. So here we're remodeling. We've got a label help ID. Now we'll call this component user.view and we'll just have a first name and a last name. Pretty simple. Okay, so now we've got two text inputs. We're reusing our component, first name, last name.
6. Using a Dedicated Form Tree
Forms are challenging with multiple values and events. Code reuse and best practices are only partially achieved with components. User component usage is not user-friendly and not conducive to team collaboration. The solution lies in using a dedicated form tree.
Now you might notice something right away here. We've got all of this data, first name, last name, and the errors for the first name and last name, which are not in our component. So we're going to have to wire those up. So let's go back up a level. Now we're in our app.view and we're going to try to use that user component we just created. So here you can see we can do something like V model and we can have multiple V models in view three. So we're going to V model the last name. We're going to V model the first name, and then we're going to pass down the last name errors and the first name errors.
Okay, not too shabby, but in reality it probably looks something more like this, where we have a lot of values and a lot of events being emitted and blurred. This is called prop drilling, where we have a bunch of information that we have to get through multiple layers of our components. So let's take this and look at our rubric here. Well, first of all, I think it's fair to say forms are just hard. There's a lot of things going on inside of this form. Basically, the components are handling a small portion of it. We've got boilerplate code, non-native inputs and accessibility. Those were pretty well handled there by our component, but there's a bunch of other stuff happening there. So did it enable code reuse? A little bit. How about encouraging best practices? To some degree, a little bit. It still made it much more challenging. Is it beneficial for all skill levels? I would say that using that user component the way that we are there on the right-hand side is not terribly user-friendly, conducive to a team of developers. I think this is going to break down. Frankly, this is going to break down. We're not doing great on our scalable frontend rubric here. How can we do better? Well, I think first we need to just admit that components are not enough. Is there a solution? Is there some way that we can make forms not break down when they're used on large teams? Some way that we can create that user component in a way that makes it easily reusable? Well, I think there is and I think it's using a dedicated form tree. Let me explain a little bit more what I'm talking about. Let's take essentially what we had in our example over here on the left-hand side. We have a form. We've got a user inside the form. We've got two text input components and inside of them, I'm showing what DOM elements are there.
7. The Limitations of Basic Form Data
The form can be represented as a small tree, consisting of a form and two inputs. Native HTML recognized this concept from the start, but the spec has not been updated since 1995.
Now we could just redraw this basically as a small tree, a small general tree here. We've got the form. Then we've got the user component, two text input components, and then we've got a bunch of DOM elements underneath. So now we've drawn a tree for this. Now interestingly, the only part of this that actually matters to the form is this. It's a very simple little tree, just a form and two inputs. That's really the fundamental form or the fundamental tree that represents our form underneath. And the interesting thing is that Native HTML actually got this right from the very beginning. It knew that when you were writing your DOM that the form tree would be some sub piece of that DOM. The problem is that that was in 1995. That's a long time ago. Back in 1995, people thought that this was an attractive way to sell to developers. So a lot has changed since then and unfortunately the spec really has not been updated at all.
8. Limitations of Basic Form Data
Basic form data has limitations. It lacks data structure, unique form data keys, form rehydration, and robust validation UX. To address these issues, we created FormKit. FormKit offers a comprehensive solution to form problems by shipping components and a unique tree architecture. Native form inputs come with built-in accessibility features, and additional turbocharged inputs are available as paid add-ons. Let's convert our example to FormKit by defining the form type and removing unnecessary bindings.
So what are some of those limitations to how basic form data works? Well first of all, you can't structure data. It's not tracking any kind of state, validity state, and so on and so forth. The form data keys are not unique. So if I have two name inputs in there or two names inside of my form, it's going to send double data. You can't rehydrate a form. So like if I have a complicated form tree and I put information in the top, it does not automatically pre-populate my form. So I need to manually wire all that up. The validation UX is quite poor. You can't transport back and errors to the front. You can't modify the input behavior. There's just a lot of issues. And this is why we created FormKit. FormKit is intended to be a solution to forms in a comprehensive way, not just shipping a bunch of UI components. So FormKit tries to tackle the breadth of the form problems and does it in two ways. One, it ships components. So in this case, we're going to handle those things that are well-suited to be addressed by components with components. But then all, and we ship, we should say, we ship every form input. Every native form input out of the box comes with components that automatically has things like help text and ARIA attributes and everything like that to make sure we're accessible. We also ship a bunch of sort of turbocharged ones, things that don't come natively out of the box in HTML, like mask inputs and dropdowns and so on and so forth. And those are part of our paid add-ons. But all of the rest of this problem set is solved with a unique architecture, a tree architecture. I want to talk more about that. Let's take our example here. This is sort of our, you know, reused. We got our text input and we're reusing it with this user component. And I'm going to just convert this to FormKit. So first of all, I'm going to take my outer form and I'm going to say FormKit type form. And then this user here, I'm just going to remove all of the bindings, all of them. And just say user component. And then that user component would look something like this.
9. Using FormKit for Seamless Form Creation
FormKit simplifies form creation by allowing data to flow seamlessly between parent and child components. Validation and structured data are easily implemented, and there's no need for event passing or prop drilling.
I'd have a FormKit type text, first name and FormKit type text, last name. And I'm done. That's it. All of the data automatically flows from the parents, the child. You'll notice that we didn't V model anything there on the user. They are automatically part of the form tree and it will work seamlessly, including things like adding validation rules. If you want to get the data from your form, all you do is put a submit handler on here and your data will automatically flow there, structured the way it was structured. So you'll get your first name and last name. And you can, of course, modify that even further.
Let's say I wanted the name to be a subkey and have structured data underneath that of the first name and last name. Well, to do that, I would just go back to my user component and I would just wrap it in what we call a group. So type group, and it has its own name. And now we end up with properly structured data. Okay. Now, if I want to put validation on here, I can just put a validation prop on. So what does that look like? This is what's essentially happening under the hood. We've got a form tree that looks something like this. We have a form and that's represented over here by this node. But then we've got this user component. And it's interesting because the user component really doesn't do anything other than structure my code further. So I've drawn it here, but it really doesn't mean anything to the form tree. Just like all those DOM elements don't mean anything to the form data, it doesn't mean anything. And then inside of here we have a group.
Now, what if I wanted to change this somehow? Well, I could just add, let's say a type number, and that would automatically get registered as part of my form tree. And if I want to get a little bit more complicated, I could have some array data and I can use a list for that. In FormKit, a list is an array of information. Here I've got a select and a check box and that would automatically get registered in my form tree. There's no further setup or plumbing required here. These are automatically going to have the data flow into my FormKit type form. You notice that we're not needing to prop drill and we're not needing to pass events up and down the chain in order to make it work.
10. Creating a CMS with Nuxt
In this demo, I will show you how to create a CMS using Nuxt. We will replace a big, old, boring form with components, making it easier to manage and understand the different sections of the page. Each component represents a specific section and contains form kit inputs. With this approach, there's no need for prop drilling or model binding, and the form rehydrates correctly when the page is refreshed.
Okay, showing is better than telling, so I'm going to do a really quick demo to give you an idea of how you can actually use this. So let me fire this up. What we're going to do is we're going to make a little CMS in Nuxt. So let me pop over here.
Okay. Here you can see a tremendously simple little website. It's got a little homepage hero. It's got a pull quote. We've got a little call to action and a pricing table and a footer. And if I go to the slash edit page for this, you can see how this page is constructed. This is just a big, old, boring form. And if I look at the code for this big, old, boring form, it looks something like this. I have some way to pull information from the backend. You can see right here, I'm pulling some information. This is just a key value store, which is something you can do out of the box with Nuxt. And then down here, I've got a form kit type form and just a painful grouping of fields. You know, here I've got the page title and the page slug, and this is a long, long page of forms.
Now, I would say that this is not tremendously approachable. It's a little bit hard to see where all of the pieces and the parts are. So what I'm going to do is I'm going to just replace this with components. So what I could do is I could snip out, for example, this call to action here, I could just delete that. And now up here, you can see I've put it into a component that has the exact same thing, call to action. So I'm going to just do that with all of these. And you can see here I've got page details, editor heroes, editor testimonial, so on and so forth. And you can see what's inside of these are very, very simple little sections that just have their own little poll quotes and whatnot. Sorry, these editor sections here. They just have their own little form kit inputs, testimonial, pricing, so on and so forth. Okay, very simple. But now, they're all part of my form and you notice, again, I don't have to do any prop drilling or model binding or anything like that. And if you come over here and refresh this page, you'll notice that everything rehydrates exactly the way it's supposed to.
11. Building a CMS-like Experience
To create a CMS-like experience, I use a form kit type repeater called sections that allows users to choose the type of section they want. Each section is rendered using components, such as homepage section and testimonial. The form rehydrates correctly when the page is refreshed, and code reuse is enabled. Best practices are encouraged and enforced in Form Kit, which provides accessible DOM.
All the data flows to where it's supposed to go. And it works. So if I wanted to update something about this page, it would automatically save and be available on the homepage. But that's not particularly exciting because I want to be able to actually have a CMS-like experience. And that's really easy to do too. I'm just going to go to my little snippets here and grab this out so we can see it. So here, all I'm going to do is I'm going to have a form kit type repeater called sections. And a repeater is exactly what it sounds like in FormKit. And then inside of here, I'm going to have a little radio input that lets you pick which type of section you want to have. And then it'll render one of those components, one of these components that we saw previously, either a page details, editor hero, so on and so forth, using views component tag. So if I save this, now you can see I actually have what looks a little bit like a real CMS. I've got my homepage section, my testimonial. I can reorder these if I want to. I don't think I want to. I'm going to put that back up to the top. And if I save this page, it should work. Here, let me change my image to a desk. Now you'll also notice that it automatically created these sections. So I could add another section here and say I want to have another pricing pay or panel or let's say I want to have a testimonial down here. This is really cool. We'll save that. And then all I need to do is make sure that my front end is no longer just directly rendering out each of these components, but instead basically does the same thing and just does something like a V4. So here you can see a component with a V4 on it. Okay, now I just go get that component map, paste it in here. Now if I come over, you can see that it's actually loading up my site the way I'd like it to. Okay, so that was a really quick look at how the Form Kit form tree works. So let's review by the rubric here. Do we enable code reuse? Absolutely, very, very simply. How about encouraging best practices? Definitely best practices are encouraged. In fact, in Form Kit, they're enforced because we ship all the accessible DOM for you.
12. Form Kit's Approachability and Features
Form Kit is approachable for all skill levels and conducive to a team of developers. It uses a single component, making it easy to learn. An honorable mention is the Form Kit schema, which allows serialization of components and forms as JSON. JSON can also include logic, such as Boolean operations and arithmetic function calls.
Is it approachable for all skill levels? I literally cannot imagine it being any easier. If there is a way to make it easier, we want to do that. And is it conducive to a team of developers? Yes, absolutely. In fact, that's one of the reasons that we use a single component is so that way it's incredibly easy to learn. All you need to do is change the type.
Now a real quick honorable mention before I sign off here is Form Kit schema. This is one of people's favorite features. It allows you basically to serialize your components and your forms as JSON. So here you can see we can do DOM elements, components, and shorthand. And even more powerful is you can actually write logic in your JSON. Things like Boolean logic and arithmetic function calls, all of that can be written directly in JSON.
I'd love to show you more, but I've got to sign off. Thank you so much. I would love it if you'd give me a follow at JPSchrader and check out some of these cool projects, including Form Kit. And a shout out to Vue School, they actually did a whole course on Form Kit. That is a great way to get started if you're wondering how. All right. Thank you so much. So the question was like, how often do you use Form Kit? Answers were always not yet, but want to try and sometimes. So yeah, not a lot of people have used it yet, but are very excited to try it. Do you have any comments? Yeah, I mean, I think that's roughly what I would expect. We're a relatively new project. And if I've learned anything about developers, it's that they take a long time to adopt some new piece of technology because you need it on your next project. Right? Like somebody heard about Form Kit today for the first time, for sure. And they're not going to use it on their next project. They're not going to even use it on the next next project because it's not a form heavy one. But when the next form heavy one comes along, then they'll remember, oh, yeah, there was that tool that I heard about one time. And it'll pop up. So yeah, I mean, that's roughly what I would expect. I mean, that's the most important of like raising visibility on some things so that people know it.
Form Kit's Advanced Features and Flexibility
Form Kit is a comprehensive solution for forms, offering advanced features like deeply nested structures, repeaters, back-end validation, and the ability to create custom inputs. With Form Kit, you can easily create reusable components and establish relationships automatically. No need for prop drilling or manual binding.
And as you said, yeah, I remember it like some PTSD of like, oh, yeah, I remember, Justin. Well, I remember one a year ago when we were in, I don't remember where, Amsterdam or something, somebody did a poll on stage and it was like like 10% of people had ever heard the name Form Kit before. Nobody had even heard of it. So the fact that some people actually use it a year later, I'm pretty happy about. That's that's that's always nice when people are using your product.
Do you also think that there is like a stability consideration that people might consider before switching or just adopting the tool? Yeah, probably. We had our 1.0 release in, I want to say September or October. So it's been 1.0 for much less than a year at this point. But now it's it's pretty stable and going smooth.
OK. I wish you the best. Thanks. Let's hop into the Q&As. So the one from Daniel, I currently use vValidate. What would be the main adventures of Form Kit or vValidate? I want a reason to consider switching. Sure. Good question. vValidate and Form Kit have probably, I would say close to the most overlap out there. Where I would sort of draw the line is vValidate is much more about validation, although they do some data aggregation as well. And Form Kit is sort of intended to be a comprehensive solution to forms. So whether that's, you know, extremely deeply nested structures and repeaters and the ability to apply back end validation wherever you need to apply it, whether it's creating custom inputs that don't really fit a mold, but then you can reuse that wherever you want. And then what we talked about on this talk today, I think, is is particularly unique where you can create a component full of Form Kit inputs and then you can reuse that component anywhere you want inside of another form without needing to do any binding. So you don't need to prop drill the values down. You don't need to prop drill the validation down. You don't need to prop drill rules down. You don't need to pass any of that kind of stuff up and down. Those relationships are automatically established for you and they're handled across the board. Even things like plugins. You know, if you want to have a plugin on a given form that can automatically pass down to a component child without you needing to prop drill it down. So those are some of the unique aspects.
Form Kit's Compatibility and TypeScript Support
Form Kit ships DOM elements and provides accessibility out of the box. It is compatible with libraries like Beautify and PrimeView, with wrappers already available. Form Kit fully supports TypeScript and offers easy handling of back-end validation. Error messages can be placed anywhere in the markup, and Zod can be used for back-end validation if desired.
And then, of course, Form Kit actually ships the DOM elements. So it's a little bit more like a UI library in that case, where we actually ship a bunch of the HTML, so that way you're accessible out of the box as well.
Prop drilling is indeed the worst. I'm going to answer, propose two questions in one go. So how compatible is Form Kit with libraries like Beautify and PrimeView? Do they play nicely together? Yeah. Good question. So there's a little bit of work that you need to do in order to wrap whatever component you're going to use in Form Kit. A bunch of people have already done this. So, for example, in Beautify or PrimeView, I know somebody already wrote a PrimeView wrapper around Form Kit that anybody can go use. And in Beautify, there's a few of them out there, although we're actually in the middle of writing our own first party Beautify wrapper. So those kinds of things will get easier over time. But yes, you can pick up basically any component, including your own component, and then you can basically just call this Create Input on it and it'll work.
Does Form Kit support TypeScript? Yeah, Form Kit. There's so much TypeScript. It's pages and pages of TypeScript. Perfect. But yeah, basically, yes. Does it handle back-end validation? That's a great question. So back-end validation, what it does is it lets you submit it wherever you want. And then when there's an error that gets sent back to the front end, it allows you to place those error messages anywhere inside of your markup. So if you have an error message that's in the second repeater item on the email field, you can very easily, from the location where you received the errors, place it back on there. Right now, we're not actually doing any back-end validation unless you choose to use Zod, which we have a first-party plugin for, and then you can reuse your Zod on the back-end and the front-end. Yeah. OK. Perfect. Yeah. So that's it in terms of questions. Thanks again for your participation and for all those answers. And yeah, see you at another Vue.js AI event. I wish you an amazing day. You sure will. Bye-bye. All right.
Comments