Repository: woylie/flop_phoenix
Pull request #458 (2025-05-03 14:15:35)

rel attributes
contributes to #411 


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fbe1e3d..1c98a4c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
 ### Changed
 
 - Use `<button>` elements for pagination if no `path` is set.
+- Add `rel` attribute to previous/next links.
 - Mark up disabled previous/next links of the pagination as
   `<a role="link" aria-disabled="true">` instead of `<span>`.
 - Update documentation for `hidden_inputs_for_filter/1` to use
diff --git a/lib/flop_phoenix.ex b/lib/flop_phoenix.ex
index f171252..0043677 100644
--- a/lib/flop_phoenix.ex
+++ b/lib/flop_phoenix.ex
@@ -445,6 +445,7 @@ defmodule Flop.Phoenix do
           page={p.previous_page}
           path={p.path_fun.(p.previous_page)}
           on_paginate={@on_paginate}
+          rel="prev"
           {@opts[:previous_link_attrs]}
         >
           {@opts[:previous_link_content]}
@@ -456,6 +457,7 @@ defmodule Flop.Phoenix do
           page={p.next_page}
           path={p.path_fun.(p.next_page)}
           on_paginate={@on_paginate}
+          rel="next"
           {@opts[:next_link_attrs]}
         >
           {@opts[:next_link_content]}
@@ -481,6 +483,7 @@ defmodule Flop.Phoenix do
           on_paginate={@on_paginate}
           target={@target}
           disabled={is_nil(p.previous_cursor)}
+          rel="prev"
           {@opts[:previous_link_attrs]}
         >
           {@opts[:previous_link_content]}
@@ -492,6 +495,7 @@ defmodule Flop.Phoenix do
           on_paginate={@on_paginate}
           target={@target}
           disabled={is_nil(p.next_cursor)}
+          rel="next"
           {@opts[:next_link_attrs]}
         >
           {@opts[:next_link_content]}
@@ -585,9 +589,18 @@ defmodule Flop.Phoenix do
   attr :page, :integer, default: nil
   attr :direction, :atom, default: nil
   attr :disabled, :boolean, default: false
+  attr :rel, :string, default: nil
   attr :rest, :global
   slot :inner_block
 
+  defp pagination_link(%{disabled: true, path: nil} = assigns) do
+    ~H"""
+    <button disabled {@rest}>
+      {render_slot(@inner_block)}
+    </button>
+    """
+  end
+
   defp pagination_link(%{disabled: true} = assigns) do
     # Disabled state of the link is expressed by omission of the href attribute
     # and addition of aria-disabled attribute. Links without href do not
@@ -605,7 +618,7 @@ defmodule Flop.Phoenix do
   defp pagination_link(%{on_paginate: nil, path: path} = assigns)
        when is_binary(path) do
     ~H"""
-    <.link patch={@path} {@rest}>
+    <.link patch={@path} rel={@rel} {@rest}>
       {render_slot(@inner_block)}
     </.link>
     """
@@ -630,6 +643,7 @@ defmodule Flop.Phoenix do
     ~H"""
     <.link
       patch={@path}
+      rel={@rel}
       phx-click={@on_paginate}
       phx-target={@target}
       phx-value-page={@page}


Test patch:
diff --git a/test/flop_phoenix_test.exs b/test/flop_phoenix_test.exs
index 53fb201..5fbfaa6 100644
--- a/test/flop_phoenix_test.exs
+++ b/test/flop_phoenix_test.exs
@@ -120,6 +120,7 @@ defmodule Flop.PhoenixTest do
 
       a = find_one(html, "a:fl-contains('Previous')")
 
+      assert attribute(a, "rel") == "prev"
       assert attribute(a, "class") == "pagination-previous"
       assert attribute(a, "data-phx-link") == "patch"
       assert attribute(a, "data-phx-link-state") == "push"
@@ -139,6 +140,7 @@ defmodule Flop.PhoenixTest do
 
       button = find_one(html, "button:fl-contains('Previous')")
 
+      assert attribute(button, "rel") == nil
       assert attribute(button, "class") == "pagination-previous"
       assert attribute(button, "data-phx-link") == nil
       assert attribute(button, "data-phx-link-state") == nil
@@ -162,6 +164,7 @@ defmodule Flop.PhoenixTest do
 
       a = find_one(html, "a:fl-contains('Previous')")
 
+      assert attribute(a, "rel") == "prev"
       assert attribute(a, "class") == "pagination-previous"
       assert attribute(a, "data-phx-link") == "patch"
       assert attribute(a, "data-phx-link-state") == "push"
@@ -227,6 +230,7 @@ defmodule Flop.PhoenixTest do
 
       assert attribute(button, "phx-value-page") == "1"
       assert attribute(button, "href") == nil
+      assert attribute(button, "rel") == nil
     end
 
     test "adds phx-target to previous button" do
@@ -325,6 +329,7 @@ defmodule Flop.PhoenixTest do
       assert attribute(previous_link, "aria-disabled") == "true"
       assert attribute(previous_link, "href") == nil
       assert attribute(previous_link, "role") == "link"
+      assert attribute(previous_link, "rel") == nil
     end
 
     test "disables previous link if on first page when using on_paginate" do
@@ -335,11 +340,11 @@ defmodule Flop.PhoenixTest do
         <Flop.Phoenix.pagination meta={@meta} on_paginate={JS.push("paginate")} />
         """)
 
-      assert previous_link = find_one(html, "a:fl-contains('Previous')")
+      assert button = find_one(html, "button:fl-contains('Previous')")
 
-      assert attribute(previous_link, "class") == "pagination-previous"
-      assert attribute(previous_link, "href") == nil
-      assert attribute(previous_link, "aria-disabled") == "true"
+      assert attribute(button, "class") == "pagination-previous"
+      assert attribute(button, "href") == nil
+      assert attribute(button, "disabled") == "disabled"
     end
 
     test "allows to overwrite previous link class and content if disabled" do
@@ -459,7 +464,7 @@ defmodule Flop.PhoenixTest do
       assert attribute(next, "role") == "link"
     end
 
-    test "renders next link on last page when using on_paginate" do
+    test "renders disabled next button on last page when using on_paginate" do
       assigns = %{meta: build(:meta_on_last_page)}
 
       html =
@@ -467,11 +472,10 @@ defmodule Flop.PhoenixTest do
         <Flop.Phoenix.pagination meta={@meta} on_paginate={JS.push("paginate")} />
         """)
 
-      assert next = find_one(html, "a:fl-contains('Next')")
+      assert next = find_one(html, "button:fl-contains('Next')")
       assert attribute(next, "class") == "pagination-next"
       assert attribute(next, "href") == nil
-      assert attribute(next, "role") == "link"
-      assert attribute(next, "aria-disabled") == "true"
+      assert attribute(next, "disabled") == "disabled"
     end
 
     test "allows to overwrite next link attributes and content when disabled" do
@@ -703,6 +707,7 @@ defmodule Flop.PhoenixTest do
       assert attribute(previous, "class") == "pagination-previous"
       assert attribute(previous, "data-phx-link") == "patch"
       assert attribute(previous, "data-phx-link-state") == "push"
+      assert attribute(previous, "rel") == "prev"
       assert href = attribute(previous, "href")
       assert_urls_match(href, "/pets", expected_query.(1))
 
@@ -717,6 +722,7 @@ defmodule Flop.PhoenixTest do
       assert attribute(next, "class") == "pagination-next"
       assert attribute(next, "data-phx-link") == "patch"
       assert attribute(next, "data-phx-link-state") == "push"
+      assert attribute(next, "rel") == "next"
       assert href = attribute(next, "href")
       assert_urls_match(href, "/pets", expected_query.(3))
     end
@@ -1112,6 +1118,7 @@ defmodule Flop.PhoenixTest do
       assert attribute(button, "data-phx-link") == nil
       assert attribute(button, "data-phx-link-state") == nil
       assert attribute(button, "href") == nil
+      assert attribute(button, "rel") == nil
       assert attribute(button, "phx-value-to") == "previous"
       assert phx_click = attribute(button, "phx-click")
       assert Jason.decode!(phx_click) == [["push", %{"event" => "paginate"}]]
@@ -1134,6 +1141,7 @@ defmodule Flop.PhoenixTest do
       assert attribute(link, "class") == "pagination-previous"
       assert attribute(link, "data-phx-link") == "patch"
       assert attribute(link, "data-phx-link-state") == "push"
+      assert attribute(link, "rel") == "prev"
       assert href = attribute(link, "href")
       assert_urls_match(href, "/pets?before=B&last=10")
 
@@ -1200,6 +1208,7 @@ defmodule Flop.PhoenixTest do
 
       assert attribute(button, "phx-value-to") == "previous"
       assert attribute(button, "href") == nil
+      assert attribute(button, "rel") == nil
     end
 
     test "adds phx-target to previous button" do
@@ -1228,9 +1237,11 @@ defmodule Flop.PhoenixTest do
         """)
 
       assert link = find_one(html, "a:fl-contains('Previous')")
+      assert attribute(link, "rel") == "prev"
       assert href = attribute(link, "href")
       assert_urls_match(href, "/pets?last=10&before=B")
       assert link = find_one(html, "a:fl-contains('Next')")
+      assert attribute(link, "rel") == "next"
       assert href = attribute(link, "href")
       assert_urls_match(href, "/pets?first=10&after=C")
 
@@ -1241,10 +1252,12 @@ defmodule Flop.PhoenixTest do
         """)
 
       assert link = find_one(html, "a:fl-contains('Previous')")
+      assert attribute(link, "rel") == "prev"
       assert href = attribute(link, "href")
       assert_urls_match(href, "/pets?first=10&after=C")
 
       assert link = find_one(html, "a:fl-contains('Next')")
+      assert attribute(link, "rel") == "next"
       assert href = attribute(link, "href")
       assert_urls_match(href, "/pets?last=10&before=B")
     end
@@ -1307,9 +1320,10 @@ defmodule Flop.PhoenixTest do
 
       assert attribute(previous_link, "class") == "pagination-previous"
       assert attribute(previous_link, "aria-disabled") == "true"
+      assert attribute(previous_link, "rel") == nil
     end
 
-    test "disables previous link if on first page when using on_paginate" do
+    test "disables previous button if on first page when using on_paginate" do
       assigns = %{meta: build(:meta_with_cursors, has_previous_page?: false)}
 
       html =
@@ -1317,12 +1331,12 @@ defmodule Flop.PhoenixTest do
         <Flop.Phoenix.pagination meta={@meta} on_paginate={JS.push("paginate")} />
         """)
 
-      assert previous_link = find_one(html, "a:fl-contains('Previous')")
+      assert previous_button = find_one(html, "button:fl-contains('Previous')")
 
-      assert attribute(previous_link, "class") == "pagination-previous"
-      assert attribute(previous_link, "href") == nil
-      assert attribute(previous_link, "aria-disabled") == "true"
-      assert attribute(previous_link, "role") == "link"
+      assert attribute(previous_button, "class") == "pagination-previous"
+      assert attribute(previous_button, "href") == nil
+      assert attribute(previous_button, "disabled") == "disabled"
+      assert attribute(previous_button, "rel") == nil
     end
 
     test "allows to overwrite previous link class and content if disabled" do
@@ -1340,13 +1354,12 @@ defmodule Flop.PhoenixTest do
         />
         """)
 
-      assert previous_link = find_one(html, "a:fl-contains('Prev')")
-      assert attribute(previous_link, "class") == "prev"
-      assert attribute(previous_link, "title") == "no"
-      assert attribute(previous_link, "href") == nil
-      assert attribute(previous_link, "aria-disabled") == "true"
-      assert attribute(previous_link, "role") == "link"
-      assert text(previous_link) == "Prev"
+      assert previous_button = find_one(html, "button:fl-contains('Prev')")
+      assert attribute(previous_button, "class") == "prev"
+      assert attribute(previous_button, "title") == "no"
+      assert attribute(previous_button, "href") == nil
+      assert attribute(previous_button, "disabled") == "disabled"
+      assert text(previous_button) == "Prev"
     end
 
     test "renders next link" do
@@ -1439,7 +1452,7 @@ defmodule Flop.PhoenixTest do
       assert attribute(next, "aria-disabled") == "true"
     end
 
-    test "renders next link on last page when using on_paginate" do
+    test "renders disabled next button on last page when using on_paginate" do
       assigns = %{meta: build(:meta_with_cursors, has_next_page?: false)}
 
       html =
@@ -1447,14 +1460,13 @@ defmodule Flop.PhoenixTest do
         <Flop.Phoenix.pagination meta={@meta} on_paginate={JS.push("paginate")} />
         """)
 
-      assert next = find_one(html, "a:fl-contains('Next')")
+      assert next = find_one(html, "button:fl-contains('Next')")
       assert attribute(next, "class") == "pagination-next"
-      assert attribute(next, "aria-disabled") == "true"
-      assert attribute(next, "role") == "link"
+      assert attribute(next, "disabled") == "disabled"
       assert attribute(next, "href") == nil
     end
 
-    test "allows to overwrite next link attributes and content when disabled" do
+    test "allows to overwrite next button attributes and content when disabled" do
       assigns = %{meta: build(:meta_with_cursors, has_next_page?: false)}
 
       html =
@@ -1469,11 +1481,11 @@ defmodule Flop.PhoenixTest do
         />
         """)
 
-      assert next_link = find_one(html, "a:fl-contains('N-n-next')")
-      assert attribute(next_link, "class") == "next"
-      assert attribute(next_link, "aria-disabled") == "true"
-      assert attribute(next_link, "href") == nil
-      assert attribute(next_link, "title") == "no"
+      assert next_button = find_one(html, "button:fl-contains('N-n-next')")
+      assert attribute(next_button, "class") == "next"
+      assert attribute(next_button, "disabled") == "disabled"
+      assert attribute(next_button, "href") == nil
+      assert attribute(next_button, "title") == "no"
     end
 
     test "raises if neither path nor event are passed" do