Page MenuHomePhabricator

Accordion: Allow the accordion to be initially open, and/or programmatic opening/closing
Open, Needs TriagePublic

Description

Right now every Accordion is initially closed, and cannot be opened programmatically (only by the user clicking on it). In some situations, users of Codex may want to create Accordions that are initially open, or may want to programmatically open and close Accordions (e.g. to create a group of Accordions where only one is open at a time).

To enable this, we could take two different approaches:

  1. Add a v-model:open prop, like the one Dialog has
    1. Make this prop required (like in Dialog). This would be a breaking change, and would also force users to set up v-model:open="open" even if they don't need the ability to control the open/closed state (which is the most common case)
    2. Make this prop optional, somehow. This would require some creativity, and we don't fully know if this is possible. We considered doing this for Tabs (where having to bind v-model:active is also annoying, because most use cases don't need it) but decided against it.
  2. Add an initiallyOpen prop, similar to the initialInputValue props in Lookup and TypeaheadSearch
    1. Don't provide the ability to programmatically read/write the open/closed state beyond the initial value. This mirrors Lookup/TypeaheadSearch, which don't allow reading/writing the input value.
    2. Add open, close methods to allow writing the open/closed state, and an isOpen method and/or an event for reading the open/closed state. Using methods for this isn't The Vue Way (TM), but it may be worth it if we decide that we want to provide this kind of control and that we don't want to use v-model.

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript

For what it's worth, I've seen both of these solutions in the wild – REI's Cedar library includes an Accordion component that uses an open prop. NaiveUI does the second approach, where you can provide a prop to set a given "collapse" panel as initially expanded. So we should just pick the approach we prefer.

One common use case of Accordion widgets is to present a list of items to the user without overwhelming them with all of the content of all items at once. Forcing developers to manage a bunch of new reactive boolean variables (one for each accordion widget they wish to display) could get annoying. That might be an argument in favor of Option 2 here.

I think option 1B might look something like this:

  • Track the open/closed state internally using a ref in the Accordion component
  • On setup, initialize that ref using the value of the open prop
  • Set a watcher on the prop, and when the prop's value changes, update the internal ref
  • When Accordion wants to change the open/closed state itself (because the user clicked the button), it updates the internal ref and then emits an update:open event

This should work both with and without a v-model:open binding (and should also work with a v-model-less :open binding). We could wrap all this logic up in a composable named something like useOptionalVModel or something.