Planning create/edit modal0:06
All right, so now I'd like to work on the modal that will allow me to both create and edit an idea. So to start, I'm thinking we have a little big block here. Big button. And when you click on it, a modal slides into view. All right, let's get to work. So I'm gonna open up idea slash index. That's the page we were just looking at. And I'm thinking right down here, let's have a card and we'll have a paragraph that says what's the idea?
And I'm thinking right down here, let's have a card and we'll have a paragraph that says what's the idea? So yeah, if I come back, we get a big um, card thing there that should ideally be clickable. Okay, next I'm gonna add just a few classes to the card. Some margin 10. Just add a little space. If we have some items within it, I don't think we will actually. So I can get rid of that. Let's make it a pointer and set a finite height.
So I can get rid of that. Let's make it a pointer and set a finite height. And now we get something like that. Okay? But now at the moment, if I click on card, you'll see it's an anchor tag by default. And maybe in this case I want it to be treated as a button. So there's a couple options here, but I'll show you something funky. We could do, we could add a prop called is and default to a, and this specifies what the tag is, right?
We could do, we could add a prop called is and default to a, and this specifies what the tag is, right? So I could do something like this. Yeah, like I said, a little funky, but it'll do the trick. So if I come back and refresh, of course by default it's going to be, uh, treated as an anchor tag. Cool. But if I were to switch back, now I can say this is a button and if I come back, yeah, you can immediately see it has a different display.
and if I come back, yeah, you can immediately see it has a different display. Uh, but now it's treated as a button and that's what I want in this case. Cool. So let's make the width full and we get what we had before, maybe with text alignment to the left. Yeah, something like that. Alright, so anyways, now I wanna say when I click on this display a modal. Okay, so let's think about it. We know that we can use Alpine, right?
Dispatching open-modal event1:47
Okay, so let's think about it. We know that we can use Alpine, right? And this might be a good candidate for an Alpine component. So let's just clean this up real quick. Um, so I could declare this as a component. Remember this is sort of like a way to say, treat this as something I can use Alpine with. That's how I think of it. And then I wanna say, all right, well when you click on me, of course, of course we can do a sanity check.
well when you click on me, of course, of course we can do a sanity check. Does that work? Yes it does. Cool. So it's active and I just wanna say like, show the modal. Now we don't have a modal yet, but I wanna send a message. I want dispatch an event that says, Hey, I, I wanna show a modal called Create Modal or something like that. Okay? So as it turns out, Alpine has support for something called dispatch
Okay? So as it turns out, Alpine has support for something called dispatch and this will fire a browser event. So let's just give it any name we want. We're gonna call it open modal. I said open modal. So let's dispatch an event called Open Modal. Next, we should probably indicate what the name of the modal is. And once again, I don't know, create, create modal. That's fine. Or maybe be more specific.
And once again, I don't know, create, create modal. That's fine. Or maybe be more specific. Maybe there's more things than just ideas in the future. So we'll call it create idea or create idea modal. Alright, so I'll show you how we can listen for this. This is going to dispatch a browser event, a window level event. This is the name and this is the detail for the event. So if I were to come back, open up the console, yeah, on the window.
So if I were to come back, open up the console, yeah, on the window. Let's just listen for that event. And in response we get an event object. And event detail will be equal to whatever you pass here, right? So if I were to change this, well actually let me just show you. Let's run it, click the button and sure enough we get the name.
Let's run it, click the button and sure enough we get the name. But if instead we want this to be an object where the name is this. Alright, well now if we were to come back, let's try it one more time. Register the event, click on it. Well, now we have an object. So of course we could pass that to console dots. Uh, log to see the full object. There we go.
Building and showing modal3:45
So of course we could pass that to console dots. Uh, log to see the full object. There we go. We got two of 'em. 'cause I registered it twice, but sure enough, this is how we can access that information. It's very, very simple. Okay, so this is just sugar that dispatches a browser event. Cool. So now, yeah, just to start, here's what we could do at the bottom of the page, let's prepare our modal and then we will tweak and refactor and extract it.
let's prepare our modal and then we will tweak and refactor and extract it. All right? So we'll have maybe a diviv to start. And we can also use dialogues by the way. In fact, that's what we use at raca. Uh, we use native dialogues, but let's just keep it simple here. So let's say to start, I am a modal. All right. And then on the diviv itself, let's, you know, position it right in middle of the screen.
And then on the diviv itself, let's, you know, position it right in middle of the screen. So I will paste in some classes. Again, this is pretty standard stuff really. I want fixed position. Inset means top left, right bottom of zero, set the Z index higher, uh, center it, set a background color, make it a little blurry. Uh, you get the idea. So now we get something like this, but of course I don't wanna see this by default.
Uh, you get the idea. So now we get something like this, but of course I don't wanna see this by default. And second, this should probably be a card. Okay, well let's do the card portion, X card. That's becoming very useful, isn't it? There we go, come back. Now we have a little card in the middle, but I don't wanna see it by default. So once again, if I want to make it interactive, then I'm going to set X data on it or on its parent.
So once again, if I want to make it interactive, then I'm going to set X data on it or on its parent. Alright, so why don't we say, um, one of the values that we bind to is show I like it nice and easy. So by default we will not show it. So that means I can say X show equals show. Okay? So if I come back, we shouldn't see it, right? We don't see it at all. But if this were true, then we would see it. Are we on the same page? Good. So think about it.
then we would see it. Are we on the same page? Good. So think about it. We could just say, all right, by default, don't show the modal, but listen for, uh, an event called Open Modal on the window. And if the name is Create Idea, and by the way, let's just keep it simple here. I don't need any more than create idea, just a string name. Anyways, if the name of the modal we wanna open is create idea, then
Anyways, if the name of the modal we wanna open is create idea, then show the show the Modal. Alright? Very easy. Here's how you can listen for a browser event. You type the name of the event like this, open modal, and we proceed it with Ible. So listen for on open modal, that's what I'm thinking in my head, but specifically we're listening for it on the window.
what I'm thinking in my head, but specifically we're listening for it on the window. And remember, in console dot dead tools, uh, we used window.at event listener. So on the window, listen for this event and then end response we can say, heard that. All right, so now if we come back, even though it's not displaying, if I click on this, we get heard that. Cool. So now we can respond to when this button is clicked
if I click on this, we get heard that. Cool. So now we can respond to when this button is clicked and when this particular event is dispatched. Cool. So if we only ever had one modal at this point, we could just say show equals true and this is gonna do the trick. Click on it and you see the modal so easy. Um, however, yeah, we could potentially have more than one modal. So what we should really do is say, well, let's set a name
we could potentially have more than one modal. So what we should really do is say, well, let's set a name for this modal and I'll just do it in line here. Name is, uh, open idea, or what, what did we call it? Create idea. Let's scroll up. Create idea. Okay, so that's our name. And then let's say, well if event, and this is like a magic variable that's passed to you, check the detail as we learned. So that will be equal to,
check the detail as we learned. So that will be equal to, I just wanna keep pushing this point that will be equal to this, right? So if event do detail equals name, then we're all set. So if they match up, then show equals true. Okay, come back, click on it and we see the modal. But let's say this was something else like, um,
Okay, come back, click on it and we see the modal. But let's say this was something else like, um, create user or something like that. Well, now if I click on it, we're not gonna see it because those two do not line up. Cool. So I'll bring that back. And we're getting started already. We have basically a functional, uh, modal. There's a bunch of missing Aria classes and things like that.
Adding transitions and close8:09
There's a bunch of missing Aria classes and things like that. We'd like maybe some transitions, but this will do it. Okay? So I'll show you how easy it is. In fact to add some transitions with Alpine, we can use X transition. So while we are entering or showing it, I can say, all right, let's set a duration of a whole second, which is too long, but fine for now, uh, to demonstrate it.
of a whole second, which is too long, but fine for now, uh, to demonstrate it. And then I can say, all right, well when we start the transition, let's begin with an opacity of zero. And when we end the transition, it should be at an opacity of a hundred or the default. So yeah, if we were to try this out, let's give it a shot refresh, and now over a second we show it, right?
let's give it a shot refresh, and now over a second we show it, right? But when we click away, which we don't have support for yet, that would be instant. So yeah, what you could do is say, enter, uh, and then swap these out for leave. So when we leave, we're gonna start at a hundred and end with zero. But remember, uh, a hundred is the default, which means you could actually get rid of these.
But remember, uh, a hundred is the default, which means you could actually get rid of these. And I think that would effectively work, right? Very, very simple to use. So with that in mind, I'm just gonna paste in my own version here that just does a little bit more. So I'm gonna set the duration pretty quick. We're gonna ease out, and then notice start at opacity of zero, and then we're just gonna translate it just a little bit.
and then notice start at opacity of zero, and then we're just gonna translate it just a little bit. That'll make it look like it's slightly sliding in. Um, and then we're done there. And then when we leave, it's gonna be a little bit quicker. We're gonna start at full opacity. And then once again, just slide back in the opposite direction. So now if I were to come back and I click on this, yeah, can you see that?
So now if I were to come back and I click on this, yeah, can you see that? It just kind of slides into view one more time and it slides end of view. Okay. But yeah, now I, I would like to click outside to remove it, but currently that doesn't work. Okay. So one of my favorite things that Alpine offers is this click, uh, event listener. Click away. This is very Caleb, uh, who built Alpine, uh, and I just love it so much.
Click away. This is very Caleb, uh, who built Alpine, uh, and I just love it so much. When you click away, then do something alert, do something. Uh, it's one of my favorite little API things he made. So notice if I click away, which means anything that is not the card, then do something right? So cool. So at that point we could say, show equals false, click on it, click away, and it goes, um, it fades out. Click, click away. So cool. Next though, just basic stuff like I should be able
Click, click away. So cool. Next though, just basic stuff like I should be able to press escape and have that go away as well. Easy enough right up here. Let's say, let's listen for when the user presses a key down and let's listen for escape. And this should be on the window level. So let's bubble up and listen at that level. And once again, just set show to false. Okay, one more time, click on this
And once again, just set show to false. Okay, one more time, click on this and then I'll just press the escape key and it's gone. So cool. Okay, so just a couple things before we wrap up. Um, if I hit refresh, let's see if I can see this. Yeah, maybe it's not gonna show up in the video, but I might see a flash of the modal before the alpine, uh, hooks in. And if I keep doing it, just pay very close attention. You might see it pop up very quickly, maybe not,
And if I keep doing it, just pay very close attention. You might see it pop up very quickly, maybe not, uh, but it's there, I promise. So if we don't wanna see that, maybe something we should do is just hard tote it. By default display is none. So not only do we set it programmatically, but we force it right when it starts, we're not gonna see anything. So now, yeah, you're not seeing it
Improving accessibility attributes11:31
starts, we're not gonna see anything. So now, yeah, you're not seeing it and I'm not seeing it either. Uh, but it will still function like it normally would. Perfect. Okay, so now the only remaining things we might wanna do is just some basic, uh, accessibility stuff, like declare that it should be treated. Uh, its role as a dialogue and there's a number of aria, uh,
Uh, its role as a dialogue and there's a number of aria, uh, attributes we should add to modals as well. So with that in mind, why don't we see if we can let Code Rabbit do this for us? Let's review uncommitted changes. All right, let's take a look. That's done. So here we go. Replace placeholder modal content. The modal contains placeholder text. I am a modal. This should be replaced. I know code rabid,
The modal contains placeholder text. I am a modal. This should be replaced. I know code rabid, so we're gonna ignore that one. Ah, yeah. And this one's actually pretty good. So we are treating this card as a button. However, in that case it could default to a type of submit. So they're suggesting that we are explicit. Fine. Let's go ahead and add that in. All right, next. Here we go. I was hoping it would do this for me so I don't have to write it out by hands.
I was hoping it would do this for me so I don't have to write it out by hands. Uh, 'cause I'm gonna be honest, I often forget. Okay, let's scroll down and they're gonna say, all right, the modal lacks essential accessibility attributes. Of course, role of dialogue. I thought we did that. Maybe not. Um, missing aria labeled by and the label. No focus trapping. Yeah. Alright, so let's see. Some of the things that adds role of dialogue,
No focus trapping. Yeah. Alright, so let's see. Some of the things that adds role of dialogue, that's the role this is playing. Uh, let's be explicit for screen readers that this is a modal. Let's give it a label. That all looks good. So sometimes it can do this for you. And then other times, uh, you pass it off to ai. I'm just gonna do it manually here and I'll add it to the bottom.
I'm just gonna do it manually here and I'll add it to the bottom. Cool. So another thing we might wanna do while we're here is set aria hidden and we can just data bind this. Uh, again, this is just screen reader stuff, so we can say if it's not showing, then it should be, um, revealed as hidden. Uh, we could do labeled by. What else might we add here? And then, uh, let's just wrap up. I'm gonna say tab index of negative one.
Extracting reusable modal component13:30
And then, uh, let's just wrap up. I'm gonna say tab index of negative one. Uh, just to make sure you can't hit tab to focus it, we'll do it programmatically. And then I think this whole thing could be its own, uh, modal component. So like before, let's go up to the components directory. I'll add a new one right here. Modal that played that PHP, paste that whole thing in. And then what else needs to be, um, dynamic?
Modal that played that PHP, paste that whole thing in. And then what else needs to be, um, dynamic? Well, the name should probably be a prop. So let's say the name and then I can delegate like, so, so I could do something like this, but actually you can see it sometimes gets a little tricky when you are combining JavaScript and PHP. Another cool thing you can do is make a string. So for example, I can use this cool JS directive
Another cool thing you can do is make a string. So for example, I can use this cool JS directive and I can say JS name. So that'll give me a JavaScript formatted string for that variable. And yeah, you, you you'll often see this used when we want to send some server side data or a variable to the front end to Alpine to JavaScript code. Alright, alright, next. Uh, I see this is hard coded,
Alright, alright, next. Uh, I see this is hard coded, I think I'm actually gonna tweak this a little bit. Let's do our header and we'll do an H two that will accept maybe some title. So we're gonna assume that every modal has a title and then I will format that, uh, just to make it a little larger and bold. Okay, so now a modal has a name and it also has a title. And then what I think I can do is let's give this an ID
Okay, so now a modal has a name and it also has a title. And then what I think I can do is let's give this an ID and this will effectively be modal title, but I want it unique. So maybe we could say modal, uh, and then let's give it the name and then a dash. I think that would work. Yeah. So we're gonna do this mostly for accessibility stuff. Not very fun, but important to do. Uh, now I can change this from Aria label to Aria
Not very fun, but important to do. Uh, now I can change this from Aria label to Aria labeled by. And once again, I can just copy this or just draw on a link there. Alright, so now maybe this gets its own div as well, just in case we need to style it at some point. We have our header, we have our main section. Alright, so now think about it. If we switch back to our index view.
Alright, so now think about it. If we switch back to our index view. Yeah, pretty much all of this can be replaced with our new modal component. That was the entire point that now the name was what was create idea. The title will be New idea. And then this would be our slot slot content. Here, come back, let's click on this. And there we go. Slides into view, slides out of view. It's working.
Here, come back, let's click on this. And there we go. Slides into view, slides out of view. It's working. All right, so in the next episode, we will actually construct the form within the modal.
