shahryarjb

shahryarjb

Adding Phoenix.LiveView.JS function for getting `getBoundingClientRect` params

When proposing or suggesting something please consider:

As my experience implementing getBoundingClientRect as Phoenix.LiveView.JS function and returns all the parameters of this JS function I mean (height, top, left and etc size) can be help full for complex client side component.

It keeps the ecosystem more clear and integrated. It can prevent the use of other client frameworks or js hook.


For example we have an accordion that is created with Phoenix component and Phoenix.LiveView.JS:

Show or open the accordion:

  def show_accordion_content(js \\ %JS{}, id) when is_binary(id) do
    js
    |> JS.show(to: "##{id}")
    |> JS.show(
      to: "##{id}-content",
      time: 500,
      transition:
        {
           "transition-all transform ease-out duration-300", 
           "will-change-[opacity] opacity-0 h-0",
           "will-change-auto opacity-100 h-[400px]"
        }
    )
  end

As you see I use hard coded height h-[400px] because browsers do not accept transition for h-auto, we have all the commands to open an accordion in Phoenix liveView as you see except some information about the element. It forces me to use hook or something like AlpineJS.

It can be an option for JS.show, JS.hide and (before or after doing operation) etc.

Thank you in advance


Refs:

Most Liked

steffend

steffend

Phoenix Core Team

@garrison already made some very good points. We don’t plan to make complex JS commands.

There are lots of improvements planned for hooks. One of them is to actually expose sticky JS commands like this:

mounted() {
  const js = this.js();
  // js.show, js.hide, js.transition, etc.
  js.toggleClass(this.el, ...);
}

Another big improvement will be colocated hooks that will allow defining the necessary JavaScript next to the components themselves.

garrison

garrison

I did not elaborate because the grid trick in question was linked above :slight_smile: Here is a StackOverflow question with more details:

Honestly you probably could find a way to do it with radio buttons and pure CSS, but I wouldn’t. What I meant was that the animation can all be done with CSS (no JS.transition needed), and then all you need is JS.toggle_class to trigger the CSS animations.

First, you wrap each item in a grid container, and then you use CSS to toggle grid-template-rows between 0fr and 1fr. You set overflow: hidden on the child (the accordion content in your case) so that it’s not visible when closed.

The CSS would look like this:

.container {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 100ms;
}
.container.open {
  grid-template-rows: 1fr;
}

.content {
  overflow: hidden;
}

The HEEx would look like this:

<div>
  <div class="container" phx-click={@open}>
    <div class="content">Foo</div>
  </div>
  <div class="container" phx-click={@open}>
    <div class="content">Bar</div>
  </div>
</div>

And then, if you want all of the other items to close when you open one, you would do this (otherwise you could just use JS.toggle_class("open")):

open =
  JS.remove_class("open", to: ".container.open")
  |> JS.add_class("open")

This is just a minimal demonstration of the mechanism, obviously you would also need some sort of title for each item to actually click on :slight_smile:

garrison

garrison

The code I’ve written to get around this issue (using the liveSocket to trigger JS commands in data- attributes) is some of my least favorite in my app - it’s obviously suboptimal. I think opening up the sticky API is inevitable, and I don’t see any obvious problems (it’s the same thing we’re already doing anyway, just directly). I would imagine the work simply hasn’t been done yet - JS commands are still relatively new and improving quickly. We only just got toggle_class, which was a big improvement :slight_smile:

Last Post!

sezaru

sezaru

I meant the sticky opts one, thanks for the link

Where Next?

Popular in Proposals: Ideas Top

AHBruns
Rethinking phx-no-feedback So, I won’t go into how phx-no-feedback works in detail, but the tl;dr is that it lets you conditionally add a...
New
munksgaard
I’m copying and pasting this issue from @Terbium-135 here verbatim, because I would be interested in such a feature as well, and because ...
New
Jskalc
Hi everyone! Recently I was thinking a lot about the way HEEX renders lists. People are generally surprised about huge payloads being sen...
New
dvartic
Would there be interest to implement a link/1 that gives to option to operate on other events? So I implemented a simple link/1 function...
New
MatinDevs
Currently, there are ongoing discussions about enhancing Phoenix LiveView, particularly focusing on improving performance and user experi...
New
jakeprem
Goal: To make JS.patch and JS.navigate more interoperable with JS.push. Scenario: Imagine making a reusable Phoenix component and you wa...
New
dogweather
Hi Phoenix community! First off, huge thanks for an amazing framework - Phoenix has been a joy to work with. I have a small UX suggestio...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42533 114
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

We're in Beta

About us Mission Statement