Let's Have a Dialog about Dialogs!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey everybody so a few years ago I was playing around with the HTML dialogue element and real quick if you're unfamiliar with that the dialogue element is sort of like browser native modals okay but yeah I don't know back then I came away thinking this is very cool but maybe not quite ready for prime time but yeah yesterday it occurred to me oh wait a minute maybe that's old news maybe I'm late to the pack and I should be using this right now and as it turns out I was right so I've been researching this quite a bit in the last day and I'd like to show you every single thing I've learned step by step let's get started now I'm going to use the layer cast source code for our example and that's a view app but yeah just keep in mind all of this can be applied to bread and butter HTML CSS and JavaScript projects all right so you can see I've set up a simple component here that says begin and if I view this in the browser this is what we get all right let's get started step one and let's start very simply imagine you have a button that says toggle modal and real quick I'll give it a class like button and button blue just to make it a little prettier okay so as you can imagine when I click on this button it should dot dot dot toggle a modal all right let's create the model so we can make use of the dialogue element just like this all right so I could say hello from the modal now if I switch back to the browser though you'll notice I don't see anything here and that's because the default display for a dialogue element is none you don't see it unless you activate it but if you want to force it to be open you can add the open attribute just like this so now we can see it right here pretty cool all right but let's turn that off so I have a button now I want to toggle the dialogue how do I do that well of course we need to listen for a click event so with vanilla JavaScript you might do something like this but I'm a view app so I can say at simple click and then I can say on click or something like that okay now I can define a function to handle that click event now once again if I were using vanilla JavaScript I might do something like this document. query selector look for the dialogue and then I can call a method show model all right that's it let's give it a shot click on the button that triggers The Click event and sure enough we have our model now it's not the prettiest thing in the world but that's okay okay uh we can fix that pretty easily with CSS and even better A lot is going on here that you may not initially notice for example while this dialogue is open notice that if I click around all these buttons everything is disabled and yeah we kind of take that for granted but if you were manually implementing a modal from scratch you would have to work on features just like that all right second if I press the Escape key it closes the dialogue and once again in the past we had to write up that code code manually so that's very cool all right so if I switch back to PHP storm yeah now that you understand the vanilla JS way to go about it if you don't mind I want to make use of view just a little bit more so here's what I would normally do in a view app I'd add a ref to the dialogue something like that and then in order to access that element I could say let dialogue equal a ref and I'll set that to null and then I can remove this function call entirely into an inline when you click on this button grab the dialogue ref and that's just giving me a reference to that Dom element so now directly on that element once again I can call show modal and yeah that just makes things a little bit cleaner uh at least to my eyes and we'll get the exact same thing which is cool all right let's move on to phase two most of the time your dialogues will wrap forms right so let's try this let's create a form and I'll have a button once again with a class of button button blue and all it says is close all right so we have a dialogue that simply closes the dialogue so if I click toggle modal we get our tiny tiny little modal here but notice if I click on it well you may not notice it in the video but that's actually refreshing the page and of course it's doing that that's the default behavior for a form it's making a get request here but we don't really want that I'm inside of a dialogue so instead on the form tag I can set method the dialogue so when I do this it's not going to uh submit to the server instead it's going to close the dialogue it will remember all of the input values and it will make them available to you when you need them okay so if I come back and try this again yeah it's going to look similar to before but rest assured it's actually not submitting to the server it's very Snappy pretty cool okay but you know what while we're here let's take a short break this is a horrible looking model so why don't we write just a little bit of CSS to make it prettier now I'm in a view single file component so I'm going to place it in the style tag down here but of course you can put it in an external CSS file whatever you want to do so let's style our dialogue and I'm hoping co-pilot can help me out here all right let's see it set a width and height of 100% yeah but why don't we set a maximum width um I'm going to keep it very simple here but in your projects you might want to do something like the maximum width can be 8 % of the viewport width uh that might be a good way to go for now though I will set a maximum width of 500 pixels we're going to make it a fixed position and I'll do inset zero so it goes top left right and bottom of zero and then for the background color let's just hard coat that to White all right let's see how that did and yeah here's what we get all right let's do a little more let's set a border radius maybe 0.5 rims come back now it's rounded next Maybe we don't need to force the height so I will remove that entirely and now it'll take up only as much as is necessary all right next why don't we add a little bit of padding all around all right and then finally I don't know maybe a box Shadow and this is going to be super developer uh how about 10 pixels of Shadow and yeah maybe black at 10% good enough for me uh find something off the shelf maybe through Tailwind that is much better now you'll notice that it's perfectly positioned and that might be because it's inheriting some margin so notice if I set margin to zero yeah and that makes sense it does push it up to the top left but yeah in our case I do want it vertically and horizontally centered so I think that makes sense all right so now yeah if I were to scroll up we might say this is pretty cool and let's start structuring things okay so generally with a modal right you have a header and then a main section and then a footer right so why don't we do that now we'll say header and I don't know maybe this is a sign up model or something like that you'll have a main section here are the steps for registration and then finally we have a footer which will usually contain uh any relevant buttons and yeah this is a fairly standard uh modal layout so if I come back here we go all right so now I don't want to make you watch this too much but I will apply some initial styling using tailwind and do notice anything unique to the implementation I will do manually down here just so that it's portable to whatever tool you use but for anything like setting a color or font weight I will use utility classes for example font bold and then maybe text for XL or something like that or maybe 3 XL and then maybe on the form tag itself we'll set space y of six and just a little bit of breathing room in between all of the elements and yeah to be honest it still doesn't look very very good but that's okay you can work on this on your own just like I will but for now in this video we're mostly focused on the implementation how do we get this thing to work in the first place okay so now notice if I toggle the modal by default uh the dialogue element will focus the first focusable element that it comes across which means if I press the return key it will hit the close button and by default the close button is going to close the dialogue not because it says close but instead because we set a method of dialogue that's how it works so notice if I remove this and come back toggle if I press return well yeah it closes it but then it makes a full uh page refresh like we learned okay so let's bring that back and to make this a little more clear what I'll do is say on the button if you are focused uh using Tailwind I can set a ring all the way around it now it'll be just a little more clear and yeah maybe you can see that there's a little ring around it because it is the currently focused button and I'll close that all right let's move on to phase three so if I toggle the model notice that I can still scroll the page behind it and yeah if you've ever implemented your own custom model you've run into this at some point or another maybe that's the functionality you want but probably not all right so how do we disable this well think about it we know if I switch back that on the HTML element I could set an overflow of hidden and that would keep me from scrolling right so if I come back and refresh the page toggle the modal yeah I'm trying to scroll right now and it's not working the only problem is even when I close the model well I can't scroll the page and that's not ideal all right but maybe we can find a way to say well while the dialogue is open then set overflow to Hidden and luckily these days with modern CSS it turns out that's really simple I'll show you I can use a has pseudo class and this one is so cool it allows me to style the h HTML tag dependent upon its descendants so for example if I were to say dialogue here well now we're saying all right set overflow to Hidden on the HTML tag if it has dialogue as a descendant but that's not enough I really want to say if it has a dialogue that is currently open all right well remember in the first step we learned that you could use an open attribute to force the dialogue open when the page loads well we can ref reference that in our selector I can say dialogue open all right so now we only set overflow to Hidden if the HTML tag has a dialogue that is currently in an open State all right let's come back to the browser and yeah I can scroll the page like normal but if I toggle the modal now you can't tell but I'm trying to scroll that page and it's not working but as soon as I close it uh that selector is no longer applied and we're back to normal problem solved all right let's move on to phase 4 is it I want to figure out how we can listen for events so for example if I want to know when this dialogue has been closed what would I do well as it turns out when you close the dialogue it fires a close event I'll show you right down here in our script tag well let's wait for the component to mount and this is just view specific stuff so you can ignore it entirely if you want just think when the component is ready to interact with uh then run some code it's sort of like a document. ready for the component but yeah again using vanilla JavaScript I could say find the dialogue and add an event listener to it and we learned the event is closed right so when it's closed trigger this callback function so I can say I was closed all right let's give it a shot ooh event is defined but never used yeah sorry you can ignore that come back toggle the modal and when I close close it sure enough we caught that event and we responded to it very cool but what if I want to fetch a value for example often you're building a confirmation model right and maybe the button choices are cancel and continue so let's Implement that we'll have one that says cancel and I'll set the value to cancel and then the other one says continue or how about proceed value is proceed okay well of course we need to detect which of these buttons the US pressed right and that's going to be stored within the return value of the dialogue I'll show you right down here this time I will accept the event and then I will alert event.target so that's going to give me the dialogue known right and then I'll say give me the return value and again that's going to be equal to one of these values here let's give it a shot all right so if I press cancel we see cancel or if I press proceed yeah now we have a way to uh proceed based upon which button the user clicked now while we're here very quickly on the footer I'm going to add just a little bit of space in between those buttons yeah that was kind of driving me crazy all right next both of these buttons being blue that's not ideal so let's change this to button cancel all right back to the browser toggle and yeah now I can cancel or proceed perfect so once again now if I were to switch over to a view specific implementation what I might do is on the dialogue element I could listen for a close event and then once again call whatever function would be appropriate I'm just going to call it on close and then I can say function on close alert the return value so once again I could accept the event or because I already have a reference to the dialogue I could say dialog. value and again that's just View's way of giving me the HTML dialogue node and then once again I could say return value on that so this would be another way uh to handle this all right come back to the browser toggle the modal cancel and yeah once again I get the exact same thing that's just more of a view specific implementation all right so hm what next what about a backdrop typically when you open a modal we fade the background in some form and again CSS to the rescue this ends up being pretty easy to accomplish so let's say right down here I could say dialogue and I specifically want to style the backdrop okay so just to make this Crystal Clear let's make a background of red and if I switch back and toggle it yeah we're we're sure it's working but we don't want red so instead why don't we do something very I don't know super developer like black at 50 um Alpha so come back and now if I toggle it yeah just notice the background Fades out just a little bit okay but maybe I don't know maybe you want to blur the background as well well in those cases we can use backdrop filter so why don't we blur it by just a little bit maybe five pixels uh just keep in mind this is somewhat of a newer property so if you're writing this all out manually uh you might need to apply a vendor prefix but because I'm using Vue and V that gets handled automatically behind the scenes okay so now yeah notice uh the background is quite a bit blurred so it doesn't take very much at all slightly darker and slightly blurred looks good to me all right let's move on to phase six is it I hope so uh I want to animate or transition the model what we have here is good for my eyes but yeah my designer at larc Adrien he wouldn't be happy with this he wants to animate it he wants to transition and slide it up from the bottom and stuff like that but right now you can't and this had me somewhat stumped so here's my understanding and maybe you can help my understanding is when we toggle the modal we're just switching it from display none to display fixed or something like that and as you know you can't animate a a display toggle so if we want to get around that as I understand it and from what I've learned we basically have to take ownership of the toggle something like this if I go to dialogue I could say display block and now notice we see it because remember the default display uh for the dialogue is none that way you don't see it when the page loads and actually real quick while I'm here notice I can see through it a little bit why don't we set a z index of something pretty high because it should usually be on top of the page like a 100 okay so now we've take an ownership of the dialogue which means we have to be responsible for showing and hiding it when necessary okay so here's what I have learned uh through Reddit and mozilla's website and uh a few questions on Twitter let me know what you think of this so we could set an opacity of zero and that will hide the dialogue so it is being rendered but it's it's effectively invisible to us right next we want to set pointer events To None just in case it would pick anything up and then what I could say is when the dialogue is open I want to change the styling for example opacity 1 and pointer event is auto so now toggle modal and yeah it seems like we've reimplemented that functionality but I don't know you can tell me I feel like we're doing something bad here is that okay is there a performance cost to that is there a layout issue related to it I feel like there must be but this is the best uh advice I've come across if we want to animate and transition the the model okay so now let's do that now one thing we could do immediately is set transition to opacity and I'm going to make it really slow just to make sure you can see it in the video all right so toggle modal and yeah now it fades in over the course of 3 seconds but check this out if I click cancel to close it it's kind of weird right and that's because the backdrop was instant so again here's a question for you is there a way to transition the backdrop you guess my understanding is right now you really can't do it maybe in the future we can but um yeah at least at the time of this recording I don't know how to do it so maybe you can help me but yeah that's a bit problematic I don't like the way that looks and granted in real life it won't be 3 seconds you know in real life I would do probably 3 seconds so it's a little harder to detect but nonetheless uh it's a bit of a problem and it's something to be aware of how do you transition the backdrop all right next what if you want to slide it up from the bottom like you see on the Lash Forum Well we'd need to use a custom animation for that so maybe right down here I would Define some key frames and we'll call this slide up and yeah this is really easy stuff start by being effectively invisible and then I want you to finish by being visible all right but next I want to push the element down so what I could do is say transform and then Translate Y uh to something tall like 100% or 100% of the viewport height that might be too much I'm not sure maybe 100% is enough let's do 100% viewport height though and then when we're done uh that will translate to zero that's one way that we can handle this okay so now I could say when the dialogue is open apply that animation slide up again I'm going to do it very slowly over the course of 3 seconds and then we'll do something like I don't know I'm a developer I can barely tell the difference ease and out let's do both okay so toggle the modal and now over the course of three seconds uh very dramatically it slides in and then if I press cancel of course it fades out okay let's tweak that to be once again something pretty fast maybe a third of a second and that looks good toggle cancel all right so now for phase seven sometimes I want my modal to take up the full width I want it to almost be like a a page sized modal right so why don't we add a toggle for that and here's what I'm thinking let's stick with a simple class so if the dialogue has a class of full then it should be treated as a full-sized dialogue okay so let's scroll down and tweak it just a little bit we'll say a dialogue that is full and actually let's change this let's make the class full size okay come back down in these cases I'm I'm going to change the maximum width so by default it's set to 500 pixels but why don't we change it to 90% of the viewport width so now if I toggle it yeah it takes up much more real estate okay next I'm going to set a height to 100% come back there we go but in these situations it becomes instantly clear that our layout isn't quite right so with that in mind why don't we say hm let's align the header the main section and the footer a little better so the parent is a form so here's what I'll do we'll say uh dialogue if it's full size grab the form and I'm going to set a display of grid okay inspect the elements and yeah now this is treated as a grid okay so now I'm going to set these rows so that the top and the bottom can be automatically sized but the middle section should expand as much as needed so what I can is say grid template rows to Auto and then one fractional unit and then Auto finally I can set a height of 100% on the form as well okay so now yeah there we go so you'll see that once again if we inspect this the main section right here can expand as much as necessary so if I were to save background of kind of a grayish color notice it's going to expand for as much room as uh is available and then by the way what we might want to do is check this out if I come back into our main section let's do this I'm just going to create a bunch of paragraphs temporarily to force uh some scrolling and let's have a look at what we have here all right toggle the modal and yeah we do get some scrolling out of the box uh natively from the dialogue but notice as I'm scrolling here I can't see the header or the footer so what I could do is right down here at the bottom I could say all right dialogue full size grab the form and then grab that Central div and we'll set overflow y to Auto that way we add scrolling to that main section okay so yeah now it'll scroll quite a bit but I can still see the header and the footer and most of the time that's going to be what you want cool yeah let's come back and clean this up all right so now for our final phase we're going to focus specifically on view and how we can organize and componentize uh much of what we've built here so I'll tell you what if you're not interested in view at all you're done bye I'll see you later yeah otherwise if you want to figure out how you can make things a little bit more flexible and reusable stick around so the first thing I would do here is extract a dedicated dialogue component if I open up my sidebar here's my project here and I already have have a folder called dialogues so I'm going to create a new view component here called dialogue and I'm not going to use typescript but if I bring back our demo project here yeah at least to start I'm going to copy the whole thing cut it and move it into the template tag here all right next I'll do the exact same thing for all of the styling so let's cut that and move it in here okay so I'm just trying to isolate everything related to a dialogue inside of this one component all right next of course we don't want to hardcode any of this this is more like the wrapper for any dialogue that we create in the future so for example maybe we could have a dialogue for signing up so I'd create a new view component called sign up uh dialogue all right so this would pull in our dialogue component and then once again yeah let's come back to dialogue and extract some of this so we have a couple choices here we could take the whole thing turn this into a slot and then paste it in here but one issue with this is if you want things to be consistent well now every single child dialogue has to either copy and paste this or retype it up right and yeah you're just introducing the possibility for things to become uh inconsistent so with that in mind why don't we extract further components so that we can reuse each individual piece for example this could be the dialogue title something like that so let's create a new view component here dialogue title and I'll paste this in and this will be our slot yeah we're just allowing for reusable HTML at this point all right let's switch back so this will say sign up next I will import that and then I'm going to do the exact same thing for the footer so let's duplicate this and this will be dialogue footer and then yeah once again I will paste in the footer but of course the individual buttons will be unique to each component so once again I can use a slot there okay so let's swap this out with dialog footer all right and once again I will import that and yeah I'll leave it at that but maybe in the future if your main section also has some unique styling then you would do something like dialogue Main and that way every individual component can reference these to ensure that everything is as consistent as possible okay what else uh let's go back to our Central parent dialogue and you'll see right up here that we are setting the class a full size but now it sounds like that should be dynamic so why don't we make that configurable as a prop we'll say full size is a Boolean and then then I could dynamically apply a class here so set full size if the full size prop is truy and by default actually let's tweak this it's a Boolean uh but by default it's set to false all right next I can remove that close event I can hide the style tag and this is basically what we have here I think we can even get rid of the ref as well so yeah the dialogue component actually is incredibly simple I like it all right so now back to our signup dialogue we pull in our parent and then we Nest our form all right so now we can return to our entry point that index test view that we've been working with the whole video and let's play around some I'm going to reference our signup dialogue and if we're starting from scratch this is what we have all right so we have a button and then we have a signup dialogue so if I come back and inspect this sure enough we have our button and our dialogue that is currently hidden okay so as we've learned we could add a ref to our component here again call it dialogue so Set uh dialogue equal an empty ref okay so now we have access to that Dom element and then I can say when you click on me ref. dialogue and yeah how do we want to do this maybe we can expose a method called show on the signup model that might be helpful or we could just do a manual query selector if we want that's the cool thing we could just say document. query selector signup dialogue. show model and that would work as well but we want the API to be nice and friendly so maybe we have a method called show all right so if I open up sign up oh by the way I got this wrong dialogues that's sign up dialog anyways if I open up this component now yeah we need to expose a function so function show and just to show you how this works we'll say time to show the dialogue but just creating the function won't expose it to the outside world so to speak so what I could do is say Define expose show okay so now we can access it outside of the component it's pretty cool all right let's give it a shot toggle the modal and time to show the dialogue so we are able to call a function on a child component from a parent so yeah maybe what we could do is apply an ID like sign up dialogue and then right here yeah again if you just want to do a simple document. query selector you could say signup dialog. show Model come back toggle the modal and now it's working just like it did before cancel but now we're in this boat where every single child model would need to reimplement some of this functionality and we don't want to do that so in situations like this we could delegate to the parent we could use a prop we could use a composable um why don't we do a composable just to demonstrate how that might work so in my composes directory I'm going to create a new uh Javascript file and we'll call it use dialogue all right so now I could export a function and by tradition we give the name of the function the same name as the file name and yeah all I'm going to do here is return uh two simple methods like show and close all right so yeah maybe we accept a selector like this and then we could say document. query selector selector do show modal and then for close yeah we could do the exact same thing just swap it out with close very very simple we're just extracting two basic basic functions but now we don't have to rewrite them for every new dialogue component that we create all right so if I switch back here yeah now I could remove this and instead import use dialogue I could call the function and that's going to of course return an object containing two methods so I will destructure them like this let show close equal use dialogue and then I will expose those to the outside world that way the parent can call a show or a close method on this individual component if it wants to I'll show you if we come back to our index view uh yeah well this should just work out of the box oh and it doesn't you know anytime you get a little bit cocky that's when it let you know it doesn't work uh cannot read property of null reading show modal on used dialogue what did I do wrong oh yeah of course this would make sense so we're trying to call a show method here but I didn't provide the selector so I would have to do this sign up dialogue and does that fix it yes it does but now I have to know what the ID is for the component there and yeah again that just makes for a crappy API so let's see if we could instantiate it here so we Define the ID on this component so let's pass it here as a selector and then it will be received here so why don't we hm why don't we say base selector and if you override that selector when you call one of these methods we'll use your selector but otherwise we will default to the base I don't know is that weird maybe we don't have to do that but I'm going to I'm going to do that for now okay and I think that should do the trick so if I come back yeah it works just like it did before but now yeah at this point we're just trying to make the API as simple as possible to use if I have a button and I want to show a dialogue then I just add a ref and then I call show on that ref all right and that's mostly it I think we're in pretty good shape here so now in our signup dialogue you have your form and you can proceed however you normally would right you'd say submit equals onsubmit you gather your data you make your Ajax request and you're all set to go and further because we've componentized some of these individual pieces like the dialogue title well now if we decide ah there should probably be a little Clos button in the top right which is pretty standard right well we can do it right here on dialogue title and then of course that will be reflected everywhere in our project that we reference a dialogue title so yeah maybe right here we'd have a button with some kind of fancy X to close it and now we can see it here okay so at this point we could say maybe Flex justify between items start yep then on the button font bold text Lo LGE and then well we have no Styles here but then when you click on it well we don't have access to the component at this point so maybe you could emit an event like click and let's emit a close event or something like that and then we can push it up a level all right Define emit close or just admit so now back to sign up dialogue yeah this would just be one way to do it another way would be to pass a prop to handle the logic yeah we could say on close then call this close uh method and that would work as well toggle the modal we click our ugly close button and yeah it works just fine all right so what was that eight or nine different faces uh that's pretty cool I hope you learned a bit and I hope you enjoyed it but keep in mind I'm still learning myself so let me know what did I miss here what am I not thinking about is the way that we animate the modal is that smart or is that idiotic it could be either I could go both ways on that one and I'd love to hear what you think all right my name is Jeffrey way I'll see you next time [Music]
Info
Channel: Laracasts
Views: 5,351
Rating: undefined out of 5
Keywords: web development, php, programming, laravel, laracasts, jeffrey way, coding
Id: ouFHUgpzsqY
Channel Id: undefined
Length: 35min 18sec (2118 seconds)
Published: Fri May 24 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.