About Page and Scroll to Top

About page with lorem ipsum text and scroll to top control that appears when the user scrolls down at the page.


About Page

A new page with sample lorem ipsum content serves as a log enough page to test the scroll to top component. app/about/page.tsx:

export default async function AboutPage() {
  return (
    <div className="container max-w-6xl py-6 lg:py-10">
      <div className="flex flex-col items-start gap-4 md:flex-row md:justify-between md:gap-8">
        <div className="flex-1 space-x-4">
          <h1 className="inline-block font-black text-4xl lg:text-5xl">
            ... Some Title ...
          </h1>
        </div>
      </div>
      <hr className="my-8" />
      <div className="flex flex-col md:flex-row gap-8 items-center md:items-start">
        <p className="text-muted-foreground text-lg py-4">
          ... Some Text ...
        </p>
      </div>
      ...
    </div>
  );
}

Scroll to Top Component

The component is fairly straightforward. Once the user scrolls past 400 pixels into the page the scroll to top button shows at the bottom right of the page. src/components/scroll-to-top.tsx:

'use client';
 
import React, { useState, useEffect } from 'react';
import { Button } from './ui/button';
import { ArrowUpToLine } from 'lucide-react';
 
export const ScrollToTop = () => {
  const [showTopBtn, setShowTopBtn] = useState(false);
 
  useEffect(() => {
    window.addEventListener('scroll', () => {
      if (window.scrollY > 400) {
        setShowTopBtn(true);
      } else {
        setShowTopBtn(false);
      }
    });
  }, []);
 
  const goToTop = () => {
    window.scroll({
      top: 0,
      left: 0,
    });
  };
 
  return (
    <>
      {showTopBtn && (
        <Button
          onClick={goToTop}
          className='fixed bottom-4 right-4 opacity-90 shadow-md'
          size='icon'
        >
          <ArrowUpToLine className='h-4 w-4' />
        </Button>
      )}
    </>
  );
};

The scroll to top component is placed in the layout under the main content (children of the layout). src/app/layout.tsx:

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { SiteHeader } from "@/components/site-header";
import { Providers } from "@/components/providers";
import { ScrollToTop } from '@/components/scroll-to-top';
 
const inter = Inter({ subsets: ["latin"] });
 
export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};
 
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className="min-h-screen bg-background font-sans antialiased">
        <Providers>
          <div className="relative flex min-h-dvh flex-col bg-background">
            <SiteHeader />
            <main className="flex-1">{children}</main>
            <ScrollToTop />
          </div>
        </Providers>
      </body>
    </html>
  );
}


Last Updated: