Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accordion doesn't support JSX content #1989

Open
Aaronius opened this issue Jun 7, 2021 · 11 comments
Open

Accordion doesn't support JSX content #1989

Aaronius opened this issue Jun 7, 2021 · 11 comments
Labels
enhancement New feature or request help wanted Extra attention is needed rsp:Accordion

Comments

@Aaronius
Copy link
Contributor

Aaronius commented Jun 7, 2021

馃悰 Bug Report

The Accordion component doesn't seem to support JSX content.

馃 Expected Behavior

I would expect that when I render this:

<Accordion>
  <Item title="Thing">
    <p>paragraph content</p>
  </Item>
</Accordion>

that I would get an accordion that works properly by allowing me to expand and collapse the item.

馃槸 Current Behavior

I get the error Unknown element <p> in collection.. If I remove the p tag and leave the paragraph content text, the accordion works fine.

馃拋 Possible Solution

馃敠 Context

I'm trying to display content that's more complex than a simple string of text.

馃捇 Code Sample

https://codesandbox.io/s/accordion-content-j4q5i?file=/src/App.js

馃實 Your Environment

Software Version(s)
react-spectrum 3.0.0-alpha.1 of the accordion component
Browser Chrome 90
Operating System Mac Catalina

馃Б Your Company/Team

Adobe Experience Platform Data Collection

馃暦 Tracking Issue (optional)

@snowystinger
Copy link
Member

it appears to be that the act of opening a leaf node causes the issue
given that all the elements within an Accordion will be leafs, we either need to fix that code in useTreeState so it doesn鈥檛 break or we need to manage our own open state, I haven鈥檛 looked at useTreeState to see if it鈥檚 better to fix it there or not

in addition, instead of item.props.children, we should really be using item.rendered like MenuItem does
https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/accordion/src/Accordion.tsx#L93 -> https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/menu/src/MenuItem.tsx#L74

a simple way to verify what I鈥檓 saying is to comment out the useAccordion https://github.com/adobe/react-spectrum/blob/main/packages/%40react-aria/accordion/src/useAccordion.ts#L50
and set isOpen to true in AccordionItem, it renders open just fine, it鈥檚 only when you click to toggle that things go south

@snowystinger
Copy link
Member

@Aaronius just copying our conversation here as well
Author:
Okay, interesting. Well, I鈥檒l share what I鈥檝e found, though it鈥檚 not entirely clear how it intersects with what you wrote and you probably already are aware of it. When you expand the AccordionItem, TreeCollection is being created and visits each item that is expanded (

if (node.childNodes && (node.type === 'section' || expandedKeys.has(node.key))) {
for (let child of node.childNodes) {
visit(child);
}
}
). In that same snippet, it calls node.childNodes in order to iterate over each child node (because those child nodes may also be expanded items, I鈥檓 assuming). The node.childNodes property is this one here:
childNodes: iterable(function *() {
if (!partialNode.hasChildNodes) {
return;
}
let index = 0;
for (let child of partialNode.childNodes()) {
// Ensure child keys are globally unique by prepending the parent node's key
if (child.key != null) {
child.key = `${node.key}${child.key}`;
}
child.index = index;
let nodes = builder.getFullNode(child, builder.getChildState(state, child), node.key, node);
for (let node of nodes) {
index++;
yield node;
}
}
})

which calls builder.getFullNode for the p child, which is where it errors out because type is p and there鈥檚 no getCollectionNode on the p component.
The reason we don鈥檛 get the issue with Menu is because there鈥檚 never an item node in expandedKeys, so node.childNodes is never accessed on the item (see the first snippet I shared).

@snowystinger
Copy link
Member

snowystinger commented Jun 8, 2021

I think the intersection here is that the TreeCollection lines you noted are for things like Section, which would have a structure like this -> <Section><Item/><Item/></Section>
the check for expandedKeys.has(node.key) isn鈥檛 quite right though for things that should be a leaf, i think the distinction and reason I鈥檓 suggesting it may be better to track this state separately of the treeState is that expandedKeys has a meaning that it expects elements like Section and like Item inside those keys

@matthewdeutsch matthewdeutsch added this to Not Groomed in Todo (out of date) via automation Nov 1, 2021
@LFDanLu LFDanLu moved this from Not Groomed to Groomed in Todo (out of date) Dec 1, 2021
@LFDanLu LFDanLu added the enhancement New feature or request label Dec 1, 2021
@andrew-grange andrew-grange mentioned this issue Apr 13, 2022
4 tasks
@AatiqUrRehman
Copy link

any workaround for this issue to show jsx content inside accordion body.

@matthewdeutsch matthewdeutsch moved this from Groomed to ListView in Todo (out of date) Jun 15, 2022
@matthewdeutsch matthewdeutsch moved this from ListView to Accordion in Todo (out of date) Jun 15, 2022
@nozokada
Copy link
Member

nozokada commented Oct 28, 2022

It apparently has to do with JSX with non-empty title so here's my hacky workaround. Not a good solution if you need the title to still appear when it's expanded.
https://codesandbox.io/s/accordion-content-forked-ncf8lo?file=/src/App.js

<Accordion
  // Setting Accordion item title to empty when it's expanded
  // to work around the issue that it breaks on rendering
  // JSX content with non-empty title
  // https://github.com/adobe/react-spectrum/issues/1989
  onExpandedChange={(keys) => {
    keys.forEach((key) => {
      accordionItemTitles = { ...accordionItemTitles, [key]: "" };
    });

    Object.keys(titles).forEach((key) => {
      if (!keys.has(key)) {
        accordionItemTitles = {
          ...accordionItemTitles,
          [key]: titles[key]
        };
      }
    });

    setAccordionItemTitles(accordionItemTitles);
  }}
>
  <Item key="item 1" title={accordionItemTitles["item 1"]}>
    <p>Item 1 Content</p>
  </Item>
  <Item key="item 2" title={accordionItemTitles["item 2"]}>
    <p>Item 2 Content</p>
  </Item>
  <Item key="item 3" title={accordionItemTitles["item 3"]}>
    <p>Item 3 Content</p>
  </Item>
</Accordion>

@danielsimao
Copy link

It apparently has to do with JSX with non-empty title so here's my hacky workaround. Not a good solution if you need the title to still appear when it's expanded. https://codesandbox.io/s/accordion-content-forked-ncf8lo?file=/src/App.js

<Accordion
  // Setting Accordion item title to empty when it's expanded
  // to work around the issue that it breaks on rendering
  // JSX content with non-empty title
  // https://github.com/adobe/react-spectrum/issues/1989
  onExpandedChange={(keys) => {
    keys.forEach((key) => {
      accordionItemTitles = { ...accordionItemTitles, [key]: "" };
    });

    Object.keys(titles).forEach((key) => {
      if (!keys.has(key)) {
        accordionItemTitles = {
          ...accordionItemTitles,
          [key]: titles[key]
        };
      }
    });

    setAccordionItemTitles(accordionItemTitles);
  }}
>
  <Item key="item 1" title={accordionItemTitles["item 1"]}>
    <p>Item 1 Content</p>
  </Item>
  <Item key="item 2" title={accordionItemTitles["item 2"]}>
    <p>Item 2 Content</p>
  </Item>
  <Item key="item 3" title={accordionItemTitles["item 3"]}>
    <p>Item 3 Content</p>
  </Item>
</Accordion>

This is possible workaround but affects the component accessibility. I would really appreciate if this issue could be solved.

@binaryartifex
Copy link

Just discovered this issue. I submitted a duplicate (#3882) just a few hours ago. The accordian/disclosure component is a very widely used component and its a damn shame that ive had my team going gang busters with react-aria until we got a flying head kick to the face with a +12 month old issue. Completely understand devs are under the pump, but this is such a prevalent component pattern its a shame that its been tucked away in the backlog basement for so long...

@snowystinger
Copy link
Member

Related #3817
We do accept contributions. Accordion isn鈥檛 particularly high on our list at the moment because there are well-defined aria patterns using dl, dd, and dt elements. If there are cross-browser inconsistencies with it, that would be a good candidate for contributing something.

@jbltx
Copy link

jbltx commented Jan 5, 2023

Answered in #3882, the quick workaround is to specify hasChildItems={false} on every Item component. I believe the problem comes from this statement.
Obviously, it is just a workaround until a real fix is done.

<Accordion
      {...props}
      expandedKeys={openKeys}
      onExpandedChange={setOpenKeys}
    >
      <Item key="files" title="Your files" hasChildItems={false}>
        <p>files</p>
      </Item>
      <Item key="shared" title="Shared with you" hasChildItems={false}>
        <p>shared</p>
      </Item>
      <Item key="last" title="Last item" hasChildItems={false}>
        <p>last</p>
      </Item>
  </Accordion>

@danielsimao
Copy link

Answered in #3882, the quick workaround is to specify hasChildItems={false} on every Item component. I believe the problem comes from this statement. Obviously, it is just a workaround until a real fix is done.

<Accordion
      {...props}
      expandedKeys={openKeys}
      onExpandedChange={setOpenKeys}
    >
      <Item key="files" title="Your files" hasChildItems={false}>
        <p>files</p>
      </Item>
      <Item key="shared" title="Shared with you" hasChildItems={false}>
        <p>shared</p>
      </Item>
      <Item key="last" title="Last item" hasChildItems={false}>
        <p>last</p>
      </Item>
  </Accordion>

It worked perfectly! Thank you @jbltx. Thank you react-spectrum for open-source all these great solutions. Cheers

@LFDanLu LFDanLu removed this from Accordion in Todo (out of date) Jan 11, 2023
@LFDanLu LFDanLu added the help wanted Extra attention is needed label Mar 8, 2023
@LFDanLu
Copy link
Member

LFDanLu commented Mar 8, 2023

Just to reiterate on what @snowystinger mentioned previously: Accordion isn't on our near term milestones so we are open to contributions for this/Accordion in general.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed rsp:Accordion
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

9 participants