Achieve a full page layout with content and attach the footer to the bottom using flexbox in Tailwindcss and Nextjs

How can I use flex-grow to make the body section fill the screen and keep the nav fixed at the bottom? I'm having trouble figuring out which elements to apply these properties to. Can anyone provide guidance on which element should have these styles?

I attempted to make the div above the nav in _app.js a flex container with flex-col, then applied flex-grow to the body section of categories/[slug].js, but it didn't work as expected.

import Head from "next/head";
    import Link from "next/link";

    import Skeleton from "react-loading-skeleton";

    import { CURSORY_ARTICLES_BY_CATEGORY_QUERY } from "../../queries/articles";

    import { useRouter } from 'next/router';
    import { useQuery } from "@apollo/react-hooks";

    const Main = () => {
        const router = useRouter()
        const { slug } = router.query;
        
        const { data, loading, error } = useQuery(CURSORY_ARTICLES_BY_CATEGORY_QUERY, {
            variables: { category: slug }
        });

    return (
        <div>
        <Head>
            <link
                rel="preload"
                href='../public/fonts/Apple.ttf'
                as="font"
                crossOrigin=""
                />
        </Head>
        <div className="max-w-full flex container bg-gray-terminal bg-image justify-around">  
            <ul className="flex flex-col font-apple">
            {   
                loading ? <Skeleton count={6} width={512} height={256}></Skeleton> : 
                error ? <p>Error: {JSON.stringify(error)}</p> :
                data.articles.map(
                        (article) => {
                            return (
                                <Link href={`/articles/${article.slug}`}>
                                    <li key={article.slug} className="rounded gird grid-cols-4 justify-between cursor-pointer my-8 mx-2 md:mx-4 lg:mx-8 text-green-terminal hover:text-white border-4 border-green-terminal hover:border-white shadow-2xl bg-gray-terminal">
                                        <h1 className="mx-4 py-4 sm:py-2 w-1/3 col-span-1 font-apple">{article.title}</h1>
                                        <p className="mx-4 text-sm py-4 sm:py-2 w-2/3 col-span-3 font-apple">{article.description}</p>
                                    </li>
                                </Link>
                            );
                        }
                ) 
            }
            </ul>
        </div>
        </div>
    );
    }

    export default function SelectedCategory() {
        return (
            <Main />
        )
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

import React from "react";

import { ApolloProvider } from "@apollo/react-hooks";
import client from "../lib/apollo";

import Nav from "../components/nav";
import Footer from "../components/footer";

import '../styles/globals.css'

function MyApp({ Component, pageProps }) {
  return ( 
    <ApolloProvider client={client}>
      <div className="flex flex-col">
        <Nav />
        <Component {...pageProps} />
        <Footer />
      </div>
    </ApolloProvider>
  );
}

export default MyApp
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

import Link from 'next/link';

export default function Footer() {
    return (
        <footer className="max-w-full container flex flex-col items-center bg-black font-apple">
            <Link href="https://twitter.com/Unenunciate">
                <svg className="my-4 cursor-pointer text-green-terminal fill-current hover:text-white" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"/></svg>
            </Link>
            <Link href="/contact">
                <div className="tracking-wider text-md mb-4 text-green-terminal hover:text-white border-green-terminal hover:border-white hover:shadow-lg">
                    Contact
                </div>
            </Link>
            <div className="text-green-terminal text-sm mb-2">
               Copyright Ⓒ 2021
            </div>
        </footer>
    );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

import CATEGORIES_QUERY from "../queries/categories";

import Link from 'next/link';
import Skeleton from "react-loading-skeleton";

import { useQuery } from "@apollo/react-hooks";

export default function Nav() {
    const { data, loading, error } = useQuery(CATEGORIES_QUERY, {
        variables: { slug: "categories" }
    });

    return (
        <div className="bg-black max-w sticky">
            <div>
                <nav className="flex justify-between container mx-auto py-4">
                    <ul>
                        <li className="group flex flex-row mx-2 text-green-terminal group-hover:text-white border-b-4 border-radius border-green-terminal hover:border-white hover:shadow-lg">
                    
                            <Link href="/">
                                <div className="flex flex-row cursor-pointer">
                                    <svg xmlns="http://www.w3.org/2000/svg" className="group-hover:text-white text-green-terminal fill-current h-5 w-5 -translate-y-2 icon  " viewBox="0 0 20 20" fill="#fff">
                                            <path fill-rule="evenodd" d="M2 5a2 2 0 012-2h12a2 2 0 012 2v10a2 2 0 01-2 2H4a2 2 0 01-2-2V5zm3.293 1.293a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 01-1.414-1.414L7.586 10 5.293 7.707a1 1 0 010-1.414zM11 12a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd" />
                                    </svg>
                                    <span className="group-hover:text-white font-apple tracking-widest">
                                        Uenunciate
                                    </span>
                                </div>
                            </Link>
                        </li>
                    </ul>
                    <ul>
                    </ul>
                    <div className="flex justify-between">
                        <ul className="flex flex-wrap mx-2 md:mx-4 lg:mx-8">
                                {   
                                    loading ? <Skeleton count={2} width={12} height={12}></Skeleton>: 
                                    error ? <p>Error: {JSON.stringify(error)}</p> :
                                    data.categories.map(
                                            (category) => {
                                                return (
                                                    <li key={category.slug} className="mx-2 md:mx-4 lg:mx-8 font-apple tracking-widest text-green-terminal hover:text-white border-b-4 border-green-terminal hover:border-white hover:shadow-lg ">
                                                        <Link href={`/categories/${category.slug}`}>
                                                            {category.name}
                                                        </Link>
                                                    </li>
                                                );
                                            }
                                    ) 
                                }
                        </ul>
                    </div>
                </nav>
            </div>
        </div>
    )
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Answer №1

To achieve the desired layout, consider applying align-items: stretch; (or use the Tailwind CSS class: items-stretch) to the main content element.

In some cases, you may need to customize the styling for the body, :root (html), and #__next elements. Below is a basic example using SASS with Next tailwind.

:root,
body,
#__next {
  @apply flex flex-col flex-1;
  @apply h-auto min-h-full w-screen max-w-full;
  @apply m-0 p-0;
  @apply overflow-y-auto overflow-x-hidden;
}

Check out this CodeSandbox example, which uses vanilla CSS due to compatibility issues with Next.js 10 in CodeSandbox.

Here are some tips:

- Use "currentColor" for SVG fill to easily color them with text color classes.

- Wrap Next links in an <a> tag as per the documentation, especially when adding additional props.

- External links should not use next/link and should have rel="nofollow noreferrer" for added security.

The provided example also incorporates these suggestions.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Restricting array elements through union types in TypeScript

Imagine a scenario where we have an event type defined as follows: interface Event { type: 'a' | 'b' | 'c'; value: string; } interface App { elements: Event[]; } Now, consider the following code snippet: const app: App ...

What steps should I take to resolve the 'Expected 1 arguments, but got 2.ts(2554)' error, so that I can successfully publish a post on firebase with an image URL?

The purpose of this RTkQuery endpoint is to create a post in Firestore. It requires two parameters: post and file, and utilizes the addDoc() and updateDoc() functions to carry out this operation. If a file is provided, the endpoint will upload the file to ...

Retrieve the nested value of an object using the specified key field

When using the DataGrid component from material-ui to display my data in a table, I encountered an issue with accessing nested values. Specifically, I have a nested array of data but am unable to retrieve the nested value within the datagrid using the key ...

Error occurs when attempting to write to a Node stream after it has already

I'm experimenting with streaming to upload and download files. Here is a simple file download route that unzips my compressed file and sends it via stream: app.get('/file', (req, res) => { fs.createReadStream('./upload/compres ...

Unselect all checkboxes except for the one that was clicked

In a project, I have 3 checkboxes that are interconnected and when one is clicked or checked, I want the others to be cleared while keeping the clicked checkbox checked. This behavior is similar to radio buttons but I cannot use radio buttons due to client ...

JSON nested error: Cannot read property 'length' of undefined

Having some trouble working with a nested array within a JSON in D3JS, specifically encountering a "property length undefined" error at the line: .attr("d", function(d) { return line(d.points); }). Below is the JSON data structure: [ { "aspectRatio" ...

Navigating up and down effortlessly using bootstrap

My webpage has a collapsible form located near the bottom, but when it's opened users must scroll down to see all of it. Is there a way to automatically scroll down when it's opened and then scroll back up when closed? Take a look at my code: & ...

Include a basic downward-pointing arrow graphic to enhance the drop-down navigation menus

I am working on a website that has drop-down menu headings styled with CSS. I am looking to enhance these certain menu headers by adding small down-facing arrows indicating they are clickable. Does anyone have any suggestions on how I can achieve this? ...

State of redux form not reflecting changes in initialValues

I am struggling to set the values in my Redux-form correctly, as the input field does not display the assigned value. Can anyone offer assistance with this issue? Below is a snippet of my code: import React from "react"; import { Field, reduxForm } from ...

Validate the date selected in a dropdown menu using JavaScript

I'm still relatively new to Javascript, just working my way through some tutorials. I have three select boxes in my HTML form as shown below. HTML Form: <table> <form id="enrolment" name="enrolment" onsubmit="return datevalidate();" action ...

Tips for designing a search bar using Angular

search : ____________ I am interested in designing a search bar functionality that automatically triggers when the user inputs 8 or more characters. The input text will be stored in a variable, the search bar will be reset, and the backend API will be che ...

Displaying items in the shopping cart across two separate columns

I have a website located at Within that page, I have included the Cart table using a woocommerce shortcode. Currently, the cart table is positioned below the billing details and payment options section. My goal is to move this cart table to be situated ...

Alert: Prop type error encountered - The prop 'open' must be defined in Snackbar component

Recently, I've been implementing jest snapshot tests into my application. The main focus is on the LoginForm component. render() { return ( ... <DynamicSnack dialogOpen={this.props.dialogOpen} snackOpen={this.props.sna ...

Shopping cart with Redux implemented in React.js

Why do I encounter an issue where clicking "Add to cart" only registers a single change even after multiple clicks, and the item doesn't get added to the cart? How can this be resolved? The desired functionality is for the 'cart' array to st ...

Does TypeGraphQl have the capability to automatically format SQL queries?

I am utilizing TypeORM in conjunction with TypeGraphQL. I am curious about the SQL query result that TypeGraphQL provides. For instance, if I have a User Table with numerous columns and a simple resolver like this: @Resolver() class UserResolver { @Q ...

Can a software be created to capture search results from the internet?

Is it feasible to create a program that can extract online search results? I am specifically interested in retrieving data from Some of the data I need include application numbers, such as 9078871 and 10595401 Although there are CAPTCHAs present, I am w ...

Initiate a fresh start with an automatic input reset

When you perform an action in the first id = "benodigheden", I believe there should be a specific outcome that then triggers a second rule for id = "benodigheden". However, I have been unsuccessful in finding information on this topic online. It seems like ...

How to Use jQuery Slice to Display the Top N Items from a Dropdown Menu

How can I display only the top 10 results from multiple UL lists in my navigation? The code snippet provided below currently works for the first list, but how can I extend this functionality to all of the lists? $(document).ready(function() { var elem ...

Extract the image URL from the href attribute using Xpath

My goal is to extract all images enclosed in href attributes from the given code snippet <div class="jcarousel product-imagethumb-alt" data-jcarousel="true"> <ul> <li> <a href="https://domain/imagefull.jpg" onclick="return false;" cla ...

changing a variable in javascript

Is there a way to successfully update the "storage" variable set in uploadify? I have a function called set_path that is designed to modify the variable by combining it with other values whenever specific content is selected. $(document).ready(function () ...