mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
93.95k stars 32.27k forks source link

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

Closed rishav001own closed 1 month ago

rishav001own commented 10 months ago

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

DiegoAndai commented 10 months ago

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

rishav001own commented 9 months ago

is there any update??

DiegoAndai commented 9 months ago

@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.

s0mn1aBaby commented 9 months ago

Upd?

ThisIsSoftwaredevv commented 9 months ago

upd?

AbdullahPS commented 7 months ago

fix please

DiegoAndai commented 6 months ago

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

bev1 commented 6 months ago

upd?

ElectricCodeGuy commented 6 months ago
'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 :)

oliviertassinari commented 6 months ago

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.

tjx666 commented 4 months ago

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

DiegoAndai commented 4 months ago

@tjx666 have you tried the workaround in this comment?

tjx666 commented 4 months ago

@DiegoAndai works, thanks

ZeeshanTamboli commented 2 months ago

This issue is duplicate of #34379

DiegoAndai commented 1 month ago

Thanks for pointing it out @ZeeshanTamboli, closing this as a duplicate of https://github.com/mui/material-ui/issues/34379