Building a Headless Ecommerce Store with Tailwind CSS, Shopify, and Next.js

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey everyone in this video we're going to build a simple e-commerce website with tailwind ui and next.js we are going to fetch some products from a shopify store using the storefront graphql api and we'll create our pages by assembling components from tailwind ui to give us a really solid foundation and starting point we'll make a few customizations to the component we use in order to meet our needs and achieve this final result i hope you're as excited as i am to dive into all of this let's do that right now [Music] okay so let's make a very quick tour of the property and discover our starting point i have created the shopify store here with a few products and each product has a title a description an image a price tags etc now shopify comes with its own front end and theming ecosystem but there is also a headless solution via the storefront graphql api and this is what we're going to use here this video is not going to be an introduction to graphql and xjs instead i'll assume that you're already familiar with these technologies there's a lot to cover here so i've already scaffolded a simple little next.js project and i'll show you what i've done so far okay so what i've done is a basic create next app installation and then on top of this i've installed tailwind css a few tailwind css plugins that are needed for the components that we're going to use as well as other dependencies like headless ui heroicons and date functions i have created a tailwind config file and you can see that we're using the just in time mode and we've extended the font family object to use the intel var fonts and like i mentioned before if i come down we're using the three tailwind css plugins here finally i've already assembled three tailwind ui components together a header a footer and a placeholder component here just to get us started all right let's do this we're going to jump into tailwind ui and try to find some components that help us put our stall together so here i am logged in in my account where i have access to the complete bundle which is marketing application ui and e-commerce and for this project we'll mix and match components from e-commerce but also marketing which is totally fine to do and so we'll start our homepage with a big bold headline so i'll come up here and check inside the hero section we're looking for something fairly simple here a big bold headline the paragraph of text and a call to action and actually this first component right here seems to be what i want we don't really want the entire component for example i don't need this navigation here but remember these components are meant to be a starting point it's totally fine and even encouraged to customize these components take what you need remove what you don't and so here we're going to come in the code tab and we'll skip all of this navigation and essentially the only parts that we want is this main section here and we'll come in the home page here and replace our placeholder element and here's what it looks like now as i mentioned a minute ago tailwind ui components are meant to be customized and it's super easy to do so by changing classes on elements let me illustrate this by making a few tweaks to this component okay so first i'm increasing the vertical spacing here and i also move the main tag one level up i'm changing the text for the headline and the paragraph and then we're going to change these buttons here we only want one button so i'll get rid of the second button and change the colors of the first button to a very dark gray almost black i also change the padding of the button and since it will have a text enterprise i wrap both the children elements in a span tag and add a divider with some internal padding okay great so that's our hero section done let's jump back intelligent ui and this time we're going to look at some e-commerce components and we want a list of products so we're going to check this product list category and let's take a look at what we've got here okay so this one with tall images here is actually the closest to what we're looking for so we could grab the whole uh component here but because we're already exporting a function in our homepage in next.js we're going to grab what we need so we'll first grab this array of products and i'll come right at the top of my page here and paste this but we're going to change this to static products just so we don't get confused with the real shopify products when they come and now we're going to grab the markup we actually don't need the wrapping bg white container since our background is already white so i'll grab everything inside of that one just before the closing main tag i'm going to paste this jsx and so i must not forget to change here products to static products and sure enough you can see this component now on our page once again we'll make some customizations and i'll walk you through those we're not doing much here like before i increase the vertical padding and then i'm going to change the aspect ratio of the images to a landscape 4x3 ratio so it works better with our product images all right looks like it's time to get real products in here like i've mentioned earlier shopify provides a graphql api called the storefront api which allows us to interact with the customer facing side of a given shopify store within the shopify admin ui we can use this graphql explorer which allows us to write and test queries and mutation against the api so since we want to query for products let's create a new query called products and we're going to look for products here and you can see that it returns a product connection but instead of having the products directly we have what's called edges and within edges we then have a node and then after the node we finally have our list of products with all the interesting fields and this is something that will come again and again these edges and node that we need to drill down through to get to our data just know that it's something useful for pagination and we're not going to use it here but this is why it's here we also need to tell how many products we want so we want the first end products so you could use 50 40. here i know that i have exactly six products so i will go with six and so we're going to drill into these edges and nodes and now in here we'll finally have all our fields like the title etc so let's think for a second what data we actually need so for each product we want an image we want a product title a product price and this bit of text which is stored in the tags of the product and finally we need a unique identifier and we're going to use the handle field for that to link each of these products to their own page we've already asked for the title let's ask for this handle field that i was mentioning we also want the tags and then we want the price so price is a little bit different it's a price range which has a min and max so we're gonna go with the mean variant and finally inside of this there is the amount and we want one more field which is the image so we have images and again we have edges and nodes here and we need to say we want the first in this case one image so we're gonna go in edges and nodes and the fields we want here is the transformed source which is a optimized image if possible and we also want the alt text so let's run this query and see what happens and bingo we have a list of six products with the fields that we've asked for and notice that it comes into a data object here all right so now i guess we need to connect our next.js site with the api and send that exact query so we can get this data and display it in the grid there are many different approaches to pull graphql data inside of a project but here we're going to keep things really simple and use the native javascript fetch method for this specific project we're building a digital asset store that means we don't have to worry about quantity of things getting out of stock we know a list of products and we know it's not going to change often so it's a perfect use case here to build static pages with nexus in other words the graphql api call is going to happen at build time and so the products will be displayed immediately to the users when the site is live since we're going to make a few different fetch calls here let's create a little abstraction so i'll create a new file in a utils folder and we're going to export an async function called storefront and this function is going to accept two arguments a query and a variables object which defaults to an empty object and inside of this function we're going to do a fetch call so const response and we're going to await fetch so we first need to pass the graphql endpoint api url for now and then we'll pass some options so the method will always be post with graphql we'll also pass some headers the first one will be content type and it's going to be application json and we also need to pass another custom header x shopify store front access token and for now i'll use access token and finally we need to pass our body and here we will have json that's stringify and we'll pass the arguments in an object so query and variables another disclaimer here i'm writing code for screencast purposes here as opposed to production ready applications i'm going to make a big assumption here and assume that there's only a happy path and the api always returns the data that i want and so in the real case scenario here you would definitely want to do error handling but here i'm going to be blissfully naive and just return response that json all right so let's replace our api url and access token values here these are okay to be displayed in public but we'll still put them in a dot end file so in x.js we can go that and that local and so i'll paste this here and we actually need to use them in the browser in the single product page and to do this in next years we need to prefix these with next underscore public and so now we can come here and fix these to use process dot end and we need to add next public and i'll grab this and prefix the other variable with it and now let's come in a home page component and remember we're going to build static pages so i'm going to use get static props here here we go and basically inside of here we want to return our products from the api so we'll use our storefront helper that we've just created so i'll come at the top here and import store front from our utils folder and down here we going to destructure our data that comes back and we will await storefront remember we can pass a query so we will pass products query which doesn't exist yet and the reason i'm destructuring data here is remember our api returns data nested in a data object so we're going to grab this entire query and i could paste it here but let's come down here and go const products query and paste that here now notice how there is no syntax highlighting and if i mess up the indentation of the query and save nothing happens now if you have the graphql extension in vs code you can use a tool called gql that will bring syntax highlighting and also when i save plop it into place but this requires an external package called graphql tag i'm going to show you a super cool trick here const gql equals string dot row i will leave it at that but by doing this you don't have to import the package and it will behave exactly like if you had it so we have a product query and we are passing it inside there so now we should be able to return our products by giving it data that products so let's take a deep breath we're going to come up here and receive these products and then let's try to console.log these products so fingers crossed let's refresh the page and look at this we have our edges with a six product nodes inside of it amazing all right now it's time to temporarily break things and we're going to try instead of static products here to use our product and remember products are nested in the edges so that's going to wreck our ui as you can see here but let's go and try replace with the correct data so instead of product here i'll go item and i will turn this implicit return into an explicit return which is going to allow me to just abstract away a couple of variables here const product equals and that's why i change name to item so we can go item that node const image to use here and here this is going to be product dot images remember it's an array with edges and we want the first edge and then grab the note and again happy path here we assuming that there's always at least one image so that node returns something all right so let's try replace things here we have a product that handle that we can use for the key and for the href i will add backticks here and we will go slash products slash and then product dot handle once again and because we're using the anchor tag here i'll quickly come up here and import link from next link so we can now wrap our anchor tag in the link and eslint is going to be very upset until i move the key and href attributes to the link itself voila thank you so let's try replace our images first i've abstracted here the image so i can go image and instead of image source we have that transformed src and the l tag is image that alt text and whoa check it out these are images coming straight from shopify into our next site cool so let's keep going we're going to change product.name to product.title and the price remember is price range that mean variant price dot amount and then here for the descriptions we're using the tags uh and here it's just a simple array so we're going to go tags zero and let's have a look this is not bad at all we just want to format the price a bit nicer so i'll quickly jump into my utils and we will export another function format price here i'm writing a quick helper function that takes a number and then formats it nicely to the australian currency for the prices we will also import format price from the same file and so now i can come here and wrap my price in format price and beautiful now our prices are displayed properly if you don't mind i'll just drink a little bit of water and you should too by the way and let's keep going alright so that's our homepage complete now with the products from shopify and if i click through one of these like paykit you can see that it takes us to slash products slash the name of the handle which is here pakit but that page doesn't exist yet so we're now going to create a dynamic route in nextgs so we're going to create a new file in pages and we're going to call this one product slash and then make it dynamic with the handle field we might find what we need in individual e-commerce components here but what we're going to do instead here is look at a product page a complete page example and then we're going to keep what we need and remove the rest so if we scroll down to the last example of this page examples category this section here is quite similar to what we want what we could do is just grab the entire component and paste this as is in our new product page so now if we come back in our product slash pay kits page and we refresh the page we now have the entire page example that we've copied here's how it looks for now and there's things we don't need like this whole navigation with the flat menus and we don't need the customer reviews section and right here there's only one related product in the example for now and we don't need this footer at all because we already have a footer down there so let's go and clean up the parts that we don't need and start working from there so we're going to remove a bunch of stuff here starting with this mobile menu section as well as the entire header contents i'm also removing the star ratings the highlight section the whole share icons section and we'll also remove this entire tab group finally i'll remove the footer section and i'll do one more thing i'll come at the top and in a related products you can see we only have one product here so i'll duplicate it four times two three four and there's still some spacing issues that we're going to fix and we'll change all the colors i remove the bottom padding and increase the top padding and change colors on the buttons and oops i see that i've made a mistake here it's not craz 700 but gray 700 here's our main button and the secondary button along with the focus states we'll also change the color of this link and this link to be grade 900 uh one more thing that we can do here is remove this view product on hover and instead have the image get to 75 opacity like on the homepage yeah perfect so it looks like we good in terms of design and now we have to bring our content from shopify right so what we want to do this time is query for a single product and the storefront api has a product by handle query but as you can expect it expects a handle so here we're going to need to use a variable so i'll go dollassign handle and to make this variable available here i need to define it so this query will have a handle variable which is a string and is required and providing that you pass the correct handle you would be able to get access to all the fields like title description and actually let's look at our design so we need the image the title we're not going to use the version but for the updated day we can use the updated ad field from shopify that's the description the price and that's about it so we have title description we want this updated ad field that i just mentioned let's grab the tags as well the price remember price range mean variant price amount and we want the first image so we want edges node transform source and alt text all right but if i try run this it's not going to return anything because i haven't provided a value for handle so let's come down there in query variables and i can open a little json object and we're going to have a handle and one of our products we know is called paykit so by defining this variable now i should be able to retrieve the pay kit product we're going to grab this query here and use it in our project so i'll come at the bottom and let's do const single product query equals gql all right so when building uh dynamic routes in a static way there's a couple more steps to do we need to generate get static props but also get static paths here we go so in this array of path we need to return the handle param for each of the six products in our shopify store so let's import storefront from utils and now in here const data equals a weight store front and here we're not using the single products query we actually want the six products so let's go gql we want to query products first six and then we want to go in edges nodes and we just want to grab the handle for each so here instead of an array data products dot edges dot map and for each product we're going to return an object so let's do an implicit return and the object will have params and then here handle and our handle is going to be our product dot node dot handle so that sounds a bit complicated but basically it's going to add the handle param to each of the routes and now with that in place we can use get static props and here we can receive these params that means that now we can grab the data here and query our single product knowing the handle which we're gonna find from the params const data equals a weight storefront and here we're going to this time pass a single product query but we're going to pass a second parameter because remember our storefront helper method here accept the second argument which is the variables object so here we're going to have an object with the handle which is the variable we need to pass params dot handle so that was a lot but finger cross it worked we're going to return our props which will have a product which will be data that product by handle and we're going to come to the top and accept our product but notice that we already have a product variable here so we're going to alias this to single product just for the time being so we can console that log it refresh the page and here's a single product and you can see the fields in there beautiful all right so let's break things and repair them we're going to get rid of the static data here and we can get rid of the aliasing here and the console log let's make our life easier once again with const image equals product dot images that edges bracket 0 that node so here we can go image that transformed source and image that alt text let's keep going down so here we have a product that title from our api and here we're going to make something slightly different instead of the version we're going to use here the tags and here we're going to have a middle dot instead of the parentheses so let's close it here and for our date we actually have the product that updated at and we can use the same here products that updated at there you go so we have our image our title the type of products but the date is not very friendly that's a quick fix i've installed a library called date functions which i can import here and we'll import format from date fns and here we're going to wrap this in format and so we're going to have a new date with that value and then dd mmm yyyy beautiful updated on 8th of september 2021. funnily enough the description has already been updated because it's using product that description here and if we keep going the price remember is price range that mean variant price that amount and we want to wrap this in a format price so let's bring it here and so now we have a nicely displayed currency and i think that's it for the single product so now we can tackle the related products so turns out that on this page we not only need the single product but we also need other products for related products so what we can do is require also other products in the same query so we get all of them into one api call so i'm actually going to come here and grab the requests for the products as well and we're going to tack that onto our single product request so we're asking for products by handle and then down here we can also ask for six products so let's save that and we're also going to add i just thought of this here we need the handle here in the product because we're going to use it to compare the related products in the current product so up here we're currently returning the one product in the product key and we can also return the product which is data that products right so let's come to the top and also accept our products let me scroll down a bit and what we're going to do now is create a const related product which is going to take these products and their edges and filter so let's grab an item we only want to keep the items where note that handle is not the same as the current product that handle and then this is a little bit simplistic but that works here we're going to slice our array from zero to four so we take all the products we remove the one that matches the current product and then whatever is left we slice and keep the first four so we always have four products to show that are not the current product so let's come down to our related products and here once again we're going to do an explicit return and i'm speeding up the video here because everything i do has been covered before i create variables for the product and the image and then use the correct data in the components for the image the product title the price which i once again wrap in the format price helper and the product tag finally i wrap the anchor tag into a next link tag and point that to the individual product page let's look at our page so this is the single product and then we have four products which are different to this product so if i go to annuals i'm now taken to annuals and i will never find it down there if i go to format goes to format etc so it's working properly all right so the last piece of the puzzle here is to hook up the pay button to send the user to the checkout flow to do that we can send a mutation to the api so let's come up here and write our mutation real quick mutation checkout create and it needs to take a variant id which is an id and so here we're going to go check out create and here we need to use an input this input has line items each line item has a variant id which is our variant id as well as a quantity which in our case is always one and this is going to return us a check out and inside that checkout there is this web url field that we want so the problem is we currently don't have that variant id here but in a single product query we could also add four variants and yes we need to go first we just want one edges nodes and here we want the id and by adding this field to our request we'll be able to use that as a variable so let's come down in our single product query here and after the images we'll add the variance which means that now i can grab the variant id from product dot variance dot edges first one node id now that we have that in place we can grab this mutation here and so i'll come right at the bottom after my query and go const checkout mutation and we'll go gql and paste a mutation here so basically now we're going to hook this up with the button click event and before we do that let's add a little piece of state import use state from react and here i'll create a piece of said const is loading set is loading use state and we'll start with false so let's come down in our button and we'll add an on click here and for now we're just going to toggle the loading states by sending it to what it's not i'm actually going to come here in the tailwind css docs in the animate spin example and i'm going to grab this svg element so here before the text if is loading is true i'm going to render this svg and so now let's focus on our button and we're going to toggle it on and off nice what we actually want to do is handle our mutation uh and redirect the user so there's gonna be a bit of code here so instead of doing it inline i'll create a checkout method and we'll come up here async function checkout so here we're going to start by setting the loading state to true set is loading true and then we're going to fire our mutation so await store front and here we want to fire our checkout mutation and as variables we want to pass remember the variant id and assuming that works properly we should receive a web url property nested in data dot checkout create that checkout and that means that we can redirect the user with window dot location dot href equals web url let's give that a try let's choose a pay kit for 59 and click on pay and look at this beautiful we have the pay kit element for 59 all right so hopefully this video gave you a good idea how to integrate tailwind ui with a headless ecommerce solution and showed you how easy it is to customize the tailwind ui components to build exactly what you need don't be afraid to make customizations this is what they were built for and this is what will make your product stand out and that about wraps it up for this video as always thank you so much for watching and i will see you in the next one bye for now [Music]
Info
Channel: Tailwind Labs
Views: 33,303
Rating: undefined out of 5
Keywords:
Id: xNMYz74zNHM
Channel Id: undefined
Length: 33min 24sec (2004 seconds)
Published: Tue Sep 21 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.