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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible solution for Accordion #59

Closed
Neophen opened this issue Oct 15, 2024 · 9 comments
Closed

Possible solution for Accordion #59

Neophen opened this issue Oct 15, 2024 · 9 comments

Comments

@Neophen
Copy link

Neophen commented Oct 15, 2024

Hey i've done this one ages ago, i've cleaned it up to look like shadcn/ui so you can basically copy paste things from here i can make the elements for ex:

https://play.tailwindcss.com/zk94DHTrbl

No javascript but most likely needs the bellow code to prevent closing on live_view updates

const liveSocket = new LiveSocket('/live', Socket, {
  hooks,
  params: { _csrf_token: csrfToken },
  dom: {
    onBeforeElUpdated: (fromEl: HTMLElement, toEl: HTMLElement) => {
      if (fromEl.hasAttribute('open')) {
        toEl.setAttribute('open', '')
      }

      return true
    }
  }
})

here's the components:

@doc """
<.accordion>
  <.accordion_item>
    <.accordion_trigger group="exclusive">
      Is it accessible?
    </.accordion_trigger>
    <.accordion_content>
      Yes. It adheres to the WAI-ARIA design pattern.
    </.accordion_content>
  </.accordion_item>
  <.accordion_item>
    <.accordion_trigger group="exclusive">
      Is it styled?
    </.accordion_trigger>
    <.accordion_content>
      Yes. It comes with default styles that matches the other components' aesthetic.
    </.accordion_content>
  </.accordion_item>
  <.accordion_item>
    <.accordion_trigger group="exclusive">
      Is it animated?
    </.accordion_trigger>
    <.accordion_content>
      Yes. It's animated by default, but you can disable it if you prefer.
    </.accordion_content>
  </.accordion_item>
</.accordion>
"""

slot :inner_block, required: true

def accordion(assigns) do
  ~H"""
  <div class="divide-y border-b">
    <%= render_slot(@inner_block) %>
  </div>
  """
end

slot :inner_block, required: true

def accordion_item(assigns) do
  ~H"""
  <div>
    <%= render_slot(@inner_block) %>
  </div>
  """
end

attr :group, :string,
  default: nil,
  doc:
    "Provide this if you want to have exclusive opens, note not widely supported yet https://caniuse.com/mdn-html_elements_details_name"

slot :inner_block, required: true

def accordion_trigger(assigns) do
  ~H"""
  <details name={@group} class="group/accordion peer/accordion">
    <summary class="flex cursor-pointer justify-between py-4 hover:underline">
      <p class="font-medium">
        <%= render_slot(@inner_block) %>
      </p>

      <svg
        class="inline-block h-6 w-6 transition-transform group-open/accordion:rotate-180"
        xmlns="http://www.w3.org/2000/svg"
        aria-hidden="true"
        fill="none"
        viewBox="0 0 24 24"
        stroke="currentColor"
        stroke-linecap="round"
        stroke-linejoin="round"
        stroke-width="1.5"
      >
        <polyline points="6 9 12 15 18 9"></polyline>
      </svg>
    </summary>
  </details>
  """
end

slot :inner_block, required: true

def accordion_content(assigns) do
  ~H"""
  <div class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-300 peer-open:grid-rows-[1fr]">
    <div class="overflow-hidden">
      <div class="pb-4 text-sm">
        <%= render_slot(@inner_block) %>
      </div>
    </div>
  </div>
  """
end
@kamaroly
Copy link
Collaborator

Thanks, @Neophen. Are you able to send a PR for review and merge?

@Neophen
Copy link
Author

Neophen commented Oct 17, 2024

Not much time but will try!

@bluzky
Copy link
Owner

bluzky commented Oct 19, 2024

Awesome!!! @Neophen, I'm looking for a way to implement accordion without js but still not find any.
Thanks for your solution.

@bluzky
Copy link
Owner

bluzky commented Oct 20, 2024

@Neophen Here is the PR based on your code, I added class attribute to support customization
#61

@bluzky
Copy link
Owner

bluzky commented Oct 21, 2024

merged #61

@bluzky bluzky closed this as completed Oct 21, 2024
@Neophen
Copy link
Author

Neophen commented Oct 23, 2024

@bluzky the name attribute on the details component is important to have exclusive accordions.
Meaning if one in the group is open, the others will be closed:

can i use

@enoonan
Copy link

enoonan commented Jan 7, 2025

Thanks so much for this! I'm a little surprised I had to manually add the JS since it looks like it was merged a few months ago:

const liveSocket = new LiveSocket('/live', Socket, {
  ...
  dom: {
    onBeforeElUpdated: (fromEl: HTMLElement, toEl: HTMLElement) => {
      if (fromEl.hasAttribute('open')) {
        toEl.setAttribute('open', '')
      }
      return true
    }
  }
})

I'm on version 0.14. Did I miss an install step or something?

@bluzky
Copy link
Owner

bluzky commented Jan 10, 2025

Hi @enoonan, what is your usecase with accordion? When adding accordion, I though it would be rendered once and not update from liveview so I omitted the js code.

@enoonan
Copy link

enoonan commented Jan 10, 2025

It's an interface that displays some interactive widgety things with buttons that push to liveview. I was having the same issue of my accordions closing when the user would click "approve". The JS snippet @/Neophen posted is very handy - I just misunderstood the comments here and thought it had been merged into the main library, so I was surprised I was even still encountering the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants