material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

[material-ui][Accordion] Content should be scrolled into view when expanded

Open rishav001own opened this issue 1 year ago • 14 comments

Steps to reproduce

Link to live example: (required)

Steps:

  1. Accordion's huge content will extend beyond the viewport when it is present.
  2. The following is an example link: https://codesandbox.io/s/distracted-sanne-rre74j?file=/demo.js 3.To expand the accordion, click the first item.
  3. Now, scroll to the bottom and select the second to enlarge.
  4. Take note of how the screen remains at the bottom of the accordion rather from being raised to the top.

Present actions At the end of the extended accordion, the screen remains

Anticipated conduct Priority should be given to the larger section's content.

Current behavior

Screen stays at end of the expanded accordion

Expected behavior

Focus should be on top of the content on the expanded section

Context

No response

Your environment

npx @mui/envinfo
  Don't forget to mention which browser you used.
  Output from `npx @mui/envinfo` goes here.

Search keywords: accordion scrolling to down

rishav001own avatar Jan 16 '24 08:01 rishav001own

Hey @rishav001own, thanks for the report!

I agree this would be a good enhancement. Here's the current behavior:

https://github.com/mui/material-ui/assets/16889233/4e88711f-a774-4bbc-ac5b-912f38836669

I added the waiting for upvotes label so the community can vote for this.

Workaround

There's a workaround using scrollIntoView and slotProps.transition.onEntered: https://codesandbox.io/p/sandbox/40625-workaround-1-4pxmn6. Here's the workaround in action:

https://github.com/mui/material-ui/assets/16889233/79d6d67a-5237-4179-a76b-d0ae650bf126

DiegoAndai avatar Jan 16 '24 14:01 DiegoAndai

is there any update??

rishav001own avatar Jan 25 '24 09:01 rishav001own

@rishav001own does the proposed workaround work for you?

Regarding implementing this behavior on Material UI's side, we'll have to wait for more upvotes.

DiegoAndai avatar Jan 25 '24 10:01 DiegoAndai

Upd?

s0mn1aBaby avatar Jan 29 '24 20:01 s0mn1aBaby

upd?

ThisIsSoftwaredevv avatar Jan 30 '24 07:01 ThisIsSoftwaredevv

fix please

AbdullahPS avatar Apr 17 '24 12:04 AbdullahPS

Hey everyone! If you wish to upvote this issue, please add a 👍🏼 (thumbs up) reaction to the description. Thanks!

DiegoAndai avatar Apr 22 '24 21:04 DiegoAndai

upd?

bev1 avatar May 02 '24 12:05 bev1

'use client';
import React, { useState, useRef } from 'react';  

const scrollToRef = useRef<(HTMLDivElement | null)[]>([]);
  


const executeScroll = (index: number) => {
    scrollToRef.current[index]?.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest'
    });
  };  


<Box
        mt={4}
        sx={{
          maxHeight: '70vh',
          overflowY: 'auto'
        }}
      >
        {courses.map((course, index) => (
          <Accordion
            key={course.id}
            onChange={() => {
              window.setTimeout(() => executeScroll(index), 500);
            }}
          >
            <AccordionSummary expandIcon={<ExpandMoreIcon />}>
              <Box
                sx={{
                  display: 'flex',
                  justifyContent: 'space-between',
                  alignItems: 'center',
                  width: '100%'
                }}
              >
                <Box sx={{ flexBasis: '70%' }}>
                  <Typography variant="h3" sx={{ fontWeight: 'bold' }}>
                    {course.name}
                  </Typography>
                  <Typography variant="body1" sx={{ mt: 1 }}>
                    {course.description}
                  </Typography>
                </Box>
                <Box sx={{ flexBasis: '10%', textAlign: 'left' }}>
                  {course.dates &&
                    course.locations &&
                    course.dates.map((date, index) => (
                      <Chip
                        key={index}
                        label={`${date} - ${
                          (course.locations && course.locations[index]) || ''
                        }`}
                        sx={{ mr: 1, mb: 1 }}
                      />
                    ))}
                  {course.link && (
                    <Box sx={{ textAlign: 'center' }}>
                      <MuiLink
                        href={`https://xxxxx.com${course.link}`}
                        target="_blank"
                        rel="noopener"
                        sx={{ textDecoration: 'none' }}
                      >
                        Tilmeld
                      </MuiLink>
                    </Box>
                  )}
                </Box>
              </Box>
            </AccordionSummary>
            <AccordionDetails>
              <div
                ref={(el) => {
                  if (el) {
                    scrollToRef.current[index] = el;
                  }
                }}
              >
                {course.image && (
                  <Box
                    sx={{
                      position: 'relative',
                      width: '100%',
                      height: '300px',
                      mb: 2
                    }}
                  >
                    <Image
                      src={course.image || '/images/aktuel.webp'}
                      alt={course.name || 'Kursusbillede'}
                      quality={100}
                      fill
                      sizes="(max-width: 768px) 100vw, 33vw"
                      style={{ objectFit: 'cover' }}
                    />
                  </Box>
                )}
                {course.course_description && (
                  <Box>
                    {isCourseDescriptionData(
                      course.course_description as string
                    ) ? (
                      (
                        course.course_description as unknown as CourseJsonB
                      ).sections.map((section, index) => (
                        <Box key={index} mt={2}>
                          <Typography variant="h4" gutterBottom>
                            {section.subheader}
                          </Typography>
                          <ul>
                            {section.checkmarks.map(
                              (checkmark, checkmarkIndex) => (
                                <li key={checkmarkIndex}>{checkmark}</li>
                              )
                            )}
                          </ul>
                        </Box>
                      ))
                    ) : (
                      <Typography>Invalid course description data</Typography>
                    )}
                  </Box>
                )}
              </div>
            </AccordionDetails>
          </Accordion>
        ))}
      </Box>

I implemented it like this here and seems to work fine :)

ElectricCodeGuy avatar May 02 '24 13:05 ElectricCodeGuy

This issue reminds me of #22152. The solution looks straightforward: overflow-anchor: auto, which is the default behavior of the platform. See https://css-tricks.com/almanac/properties/o/overflow-anchor/#aa-demo

I can't reproduce the issue in #22152 in the latest version of Chrome, so we might want to revert #22292 to close this issue.

oliviertassinari avatar May 02 '24 20:05 oliviertassinari

My solution:

const handleChange = (event: SyntheticEvent<Element, Event>, expanded: boolean) => {
  onChange?.(event, expanded);

  if (expanded) {
    setTimeout(() => {
      accordionRef.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    }, theme.transitions.duration.standard);
  }
};

Any simple resolution for current now? @oliviertassinari

tjx666 avatar Jun 30 '24 16:06 tjx666

@tjx666 have you tried the workaround in this comment?

DiegoAndai avatar Jul 10 '24 15:07 DiegoAndai

@DiegoAndai works, thanks

tjx666 avatar Jul 10 '24 17:07 tjx666

This issue is duplicate of #34379

ZeeshanTamboli avatar Sep 08 '24 05:09 ZeeshanTamboli