What is the best way to implement an AppBar that fades in and out when scrolling within a div?

I'm trying to implement a Scrollable AppBar that hides on scroll down and reappears when scrolling up.

Check out this image for reference

To achieve this functionality, I am following the guidelines provided by Material-UI documentation

export default function HideAppBar(props) {
  return (
    <React.Fragment>
      <div style={{ height: "100px", width: "100px", overflow: "auto" }}>
        {" "}
        External content
      </div>
      <CssBaseline />
      <div style={{ height: "400px", width: "300px", overflow: "auto" }}>
        <HideOnScroll {...props}>
          <AppBar style={{ position: "inherit" }}>
            <Toolbar>
              <Typography variant="h6">Scroll to Hide App Bar</Typography>
            </Toolbar>
          </AppBar>
        </HideOnScroll>

        <Toolbar />
        <Container>
          <Box my={2}>
            {[...new Array(12)]
              .map(
                () => `Cras mattis consectetur purus sit amet fermentum.
Cras justo odio, dapibus ac facilisis in, egestas eget quam.
Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
Praesent commodo cursus magna, vel scelerisque nisl consectetur et.`
              )
              .join("\n")}
          </Box>
        </Container>
      </div>
    </React.Fragment>
  );

View this demo on CodeSandbox

If you're encountering issues where the AppBar does not show when scrolling up, make sure to scroll all the way back to the top before expecting it to appear again.

Answer №1

The solution to this problem lies in

  • implementing an eventlistener for scrolling within our specified div
  • determining the direction of the scroll (up or down) by comparing the scrollPosition in our state
  • managing the css to display/hide the AppBar accordingly

relevant JavaScript:

import React, { useState, useEffect } from "react";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import Typography from "@material-ui/core/Typography";
import CssBaseline from "@material-ui/core/CssBaseline";
import Box from "@material-ui/core/Box";
import Container from "@material-ui/core/Container";

export default function HideAppBar(props) {
  const [scrollPosition, setScrollPosition] = useState(0);
  const [showBar, setShowBar] = useState(false);

  useEffect(() => {
    document
      .getElementById("insideDiv")
      .addEventListener("scroll", handleScroll);
  });

  const handleScroll = event => {
    const newScrollPosition = event.target.scrollTop;
    setScrollPosition(newScrollPosition);
    if (scrollPosition && scrollPosition > newScrollPosition) {
      setShowBar(true);
    } else {
      setShowBar(false);
    }
  };

  return (
    <React.Fragment>
      <div style={{ height: "100px", width: "100px", overflow: "auto" }}>
        {" "}
        External content
      </div>
      <CssBaseline />
      showBar? {showBar.toString()}
      <div
        id="insideDiv"
        style={{ height: "400px", width: "300px", overflow: "auto" }}
      >
        <AppBar
          style={
            showBar
              ? {
                  position: "absolute",
                  top: "120px",
                  width: "280px",
                  left: "0"
                }
              : { position: "inherit" }
          }
        >
          <Toolbar>
            <Typography variant="h6">Scroll to Hide App Bar</Typography>
          </Toolbar>
        </AppBar>

        <Toolbar />
        <Container>
          <Box my={2}>
            {[...new Array(12)]
              .map(
                () => `Cras mattis consectetur purus sit amet fermentum.
Cras justo odio, dapibus ac facilisis in, egestas eget quam.
Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
Praesent commodo cursus magna, vel scelerisque nisl consectetur et.`
              )
              .join("\n")}
          </Box>
        </Container>
      </div>
      Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus
      ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur
      ac, vestibulum at eros. Praesent commodo cursus magna, vel scelerisque
      nisl consectetur e Cras mattis consectetur purus sit amet fermentum. Cras
      justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus,
      porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus
      magna, vel scelerisque nisl consectetur e Cras mattis consectetur purus
      sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget
      quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
      Praesent commodo cursus magna, vel scelerisque nisl consectetur e Cras
      mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac
      facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac,
      vestibulum at eros. Praesent commodo cursus magna, vel scelerisque nisl
      consectetur e
    </React.Fragment>
  );
}

forked and updated codesandbox here

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

How to show a placeholder in a select input using ReactJS

I'm currently trying to incorporate placeholder text into a select input field using ReactJS, but it doesn't seem to be working as intended. Here is the code snippet I am working with: <Input type="select" placeholder="placeholder"> ...

ReactJS integration issue with Material Design Lite (import/require problem)

I am currently integrating Google's Material Design Lite with ReactJS. Specifically, I am utilizing the Spinner Loading and Text Field components from the MDL library. However, I am encountering an issue when switching routes using React Router. The ...

What is the most effective approach for addressing errors in both the server and client sides while utilizing nodejs and express?

Seeking the most effective approach for handling errors in a response - request scenario. Here is an example of a route that receives a request: app.get('/getInfo', function (req, res, next) { let obj = {} try { obj = { ...

JSON data is returned as Object Object

Trying to work with a JSON object and need to stringify it for localStorage: $http.post('http://localhost:8000/refresh', { name: $scope.name, email: $scope.email, token: $rootScope.devToken, platform: ionic.Platform.platform() }).then( ...

Searching for large images in gatsby-image: a step-by-step guide

Seeking advice on using gatsby-image for a custom lightbox gallery. Inquiry: export const getAllPhotos = graphql` query GetAllPhotos { allStrapiPortfolio { photos: nodes { categories { name } ...

Scrollbar customization feature not functional in Firefox browser

I recently finished developing a website and I have customized the main vertical scrollbar. Unfortunately, I am facing an issue where it works well on Google Chrome and Safari but not on Mozilla Firefox. Does anyone have any suggestions on how to trouble ...

When incorporating sequelize's belongsTo and hasOne methods, you may encounter an issue where the call stack size surpass

Within my Discussion entity, I have: Discussion.hasOne(sequelize.import('./sound'), { relations: false }) While in the Sound entity, the relationship is defined as: Sound.belongsTo(sequelize.import('./discussion')) To load t ...

How to choose `optgroup` in Vue 1.x

In previous iterations of vue.js, developers had the ability to generate a dynamic select list utilizing optgroups similar to the example found here. In the latest versions of vue, the documentation suggests using v-for within the options instead of optgr ...

javascript unable to change the text in the textarea

My application takes user input from a textarea element, calls an API to retrieve values, and then compares those values against a list of known "badwords." If a match is found, the word is highlighted in red to indicate it is spelled incorrectly. The pro ...

What methods can I use to adjust the selected option according to the value in the database?

To introduce you to my work, I have a table filled with data from a database that functions as a CRUD - Create, Read, Update, Delete table. Within this table, there is a column where EDIT and DELETE buttons are located. Clicking on the EDIT button trigger ...

Creating index.js files that export each of the thousands of components

As I explore libraries like material-ui, it becomes evident that there is a mechanism in place to export numerous components from an index.js file all at once. For example, when examining this link, it seems implausible for this file to have been manually ...

The checkbox filter in Angular 6 has the ability to replace the previously selected

I've been working on creating a filter system using checkboxes. Below is a snippet of the code I'm currently using: filter.pipe.ts import { Pipe, PipeTransform, Injectable } from '@angular/core'; @Pipe({ name: 'filter2' }) ...

Consistently scaling the Embla carousel slides for a seamless presentation experience

In my current project, I am utilizing Embla Carousels and aiming to incorporate a smooth slide scaling effect as users scroll through. The idea is for slides to enlarge the closer they get to the left edge of the carousel container, then decrease in size r ...

What methods can I utilize to eliminate npm run build errors?

I'm currently facing an interesting issue while trying to run npm build and I can't seem to figure out what's causing it. Is there a way to execute the build process even with errors? $ npm run build > <a href="/cdn-cgi/l/email-prote ...

Unravel the JSON structure

Here is the JSON response I received from an AJAX call: [{"id":null,"period":null,"until":null,"agent_id":"15","agent_zlecajacy_id":"15","offer_id":null,"status":"1","tytul":"Pobranie ksi\u0105g","tresc":"Pobranie ksi\u0105g","data_aktualizacji" ...

Mysterious extra space appearing on the right side of the left scroll div in Chrome

I am currently working with a table that dynamically increases in content when a button is clicked. I have successfully implemented a scroll on the right side to handle overflow. However, I encountered an issue when trying to change the scroll to the left ...

I encountered an issue with Array map when attempting to access the data during a dynamic rendering process

function UserTransactionsComponent1() { const [accounts, setAccounts] = useState(); useEffect(() => { async function fetchData() { const res = await fetch( 'https://proton.api.atomicassets.io/atomicassets/v1/accounts' ...

Working with conditional rendering in React Native allows us to easily change text based on different conditions. By utilizing

Hello fellow React Native beginners! I'm currently working on a feature where the text output on the screen changes based on the time of day. Specifically, I want the screen to display 'Morning' if it's morning, 'Afternoon' i ...

Encountering a "require is not defined" error when trying to launch a Selenium

I have developed a basic selenium application and now I am looking to implement a graphical user interface for it. Here is the code snippet: index.html: <html> <head> <meta charset="UTF-8" /> <title>Selenium Ap ...

The absence of color gradations in the TypeScript definition of MUI5 createTheme is worth noting

Seeking to personalize my theme colors in MUI5 using TypeScript, I am utilizing the createTheme function. This function requires a palette entry in its argument object, which TypeScript specifies should be of type PaletteOptions: https://i.stack.imgur.com ...