Rails: Turbo Framesで追加されるDOMノードをうまく扱う方法(翻訳)
私はReact方面の出身で、Reactとの付き合いも長いので、それ以来ずっとReactのファンです。
そんな私も最近Hotwireを使うようになって、たちまちHotwireに惚れ込んでしまいました。Hotwireのシンプルな方法論と効率の良さは印象的です。しかしHotwireと付き合ううちにいくつか面食らった点があります。
面食らった点の1つは、DOM内でのTurbo Framesの振る舞いです。
Reactなら、<Fragment>
(またはショートハンドの<>
)を使えばDOM構造に余計なノードが追加されることを簡単に回避できます。
しかし<turbo-frame>
タグはDOM内に物理的に埋め込まれるため、表示やスタイルで思わぬ問題が発生することがあります。
最初はシンプルな例を考えてみましょう。
LPレコードのコレクションを表示するアプリで、LPレコードのリストを表示するときに、リストの最初の要素を「New Record」の追加ボタンにしたいとします。
基本的なマークアップは以下のとおりです。
<ul class="grid grid-cols-4 gap-8">
<li>
<div class="w-full bg-black aspect-square">
<%= link_to new_record_path, :class => "bg-blue-500 text-white px-2 py-1 rounded-md size-full flex items-center justify-center" do %>
<span class="text-2xl text-center"><span class="text-4xl">+</span><br/> New Record</span>
<% end %>
</div>
</li>
<% @records.each do |record| %>
<li class="relative">
<%= link_to record_path(record) do %>
<div class="w-full bg-black aspect-square">
<%= image_tag record.cover, class: "size-full object-contain" if record.cover.present? %>
</div>
<% end %>
</li>
<% end %>
</ul>
上は以下のように表示されるはずです。
次に、これらのレコードを以下のようにTurbo Frameでラップして、「New Record」追加ボタン(new_record_path
)はその外側に配置したいとします。
<ul class="grid grid-cols-4 gap-8">
<li>
<div class="w-full bg-black aspect-square">
<%= link_to new_record_path, :class => "bg-blue-500 text-white px-2 py-1 rounded-md size-full flex items-center justify-center" do %>
<span class="text-2xl text-center"><span class="text-4xl">+</span><br/> New Record</span>
<% end %>
</div>
</li>
<%= turbo_frame_tag "records" do %>
<% @records.each do |record| %>
<li class="relative">
<%= link_to record_path(record) do %>
<div class="w-full bg-black aspect-square">
<%= image_tag record.cover, class: "size-full object-contain" if record.cover.present? %>
</div>
<% end %>
</li>
<% end %>
<% end %>
</ul>
しかし結果は期待どおりになりませんでした。
🔗 何が問題か
Turbo Framesは新しい要素としてDOMに挿入されるため、レイアウトが崩れる可能性があります。フレームがgridの第2カラムに挿入されると、全レコードもそこに挿入されます。
🔗 修正方法
修正は可能です!解決方法の1つは、フレームをCSSで「透明」にするという昔ながらの方法です。必要な作業は、display
プロパティをcontents
に設定することだけです。
.your-turbo-frame {
display: contents;
}
これでフレームが透明になり、LPレコードのリストが正しく表示されるようになりました。 🎉
概要
元サイトの許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。