結論
- Turbo Framesを用いて
<table>タグ内の<tr>タグを入れ替えることはできない - 理由はHTML Living Standard(HTMLの標準仕様)で許可されていないから
背景
Ruby on RailsでTurbo Framesを利用した話
こんな感じで、テーブルの行をインライン編集できるフォームを作りたかった
<tr>部分をturbo_frame_tagで囲めば、その行だけを部分的に入れ替えられるんじゃね?と考えた
問題
<table>タグ内の<tr>タグをturbo_frame_tagで囲って入れ替えようとしたところ、レンダリングされた<turbo-frame>タグが<table>タグの外に押し出された
実際のソースコード
app/views/cats/index.html.erb
<table>
<thead>
<tr>
<th>名前</th>
<th>年齢</th>
<th></th>
</tr>
</thead>
<tbody>
<% @cats.each do |cat| %>
<%= turbo_frame_tag cat do %> <!-- turbo_frame_tagで囲っている -->
<tr>
<td><%= cat.name %></td>
<td><%= cat.age %></td>
<td class="d-flex justify-content-end">
<%= link_to '編集', edit_cat_path(cat) %>
<%= button_to '削除', cat_path(cat), method: :delete, data: { turbo_confirm: '本当に削除しますか?' }, class: 'btn btn-danger' %>
</td>
</tr>
<% end %>
<% end %>
</tbody>
</table>
実際にレンダリングされたHTML構造
上記のコードをブラウザでレンダリングすると、期待した構造にはならず<turbo-frame>がテーブル外に分離される
<!-- 期待した構造 -->
<tbody>
<turbo-frame id="cat_1">
<tr>...</tr>
</turbo-frame>
</tbody>
<!-- 実際にレンダリングされた構造 -->
<turbo-frame id="cat_1"></turbo-frame> <!-- tableの外に押し出される -->
<turbo-frame id="cat_2"></turbo-frame>
<turbo-frame id="cat_3"></turbo-frame>
<table>
<tbody>
<tr>...</tr> <!-- turbo-frameと完全に分離 -->
<tr>...</tr>
<tr>...</tr>
</tbody>
</table>
原因
<tbody>タグの子要素として許可されているのは<tr>タグのみであり、<turbo-frame>のようなカスタム要素は含められない
ブラウザのHTMLパーサーは、仕様に違反する要素を自動的に修正しようとするため、<turbo-frame>がテーブルの外に押し出される
解決策
<table>タグの代わりに、CSS Grid や Flexbox を使った<div>ベースのレイアウトに変更する
<div>は子要素の制約が緩く、<turbo-frame>のようなカスタム要素を内包してもブラウザのパーサーに弾かれない。そのためturbo_frame_tagによる行単位の差し替えが素直に実現できる
感想
-
tableの仕様を初めてちゃんとみた - HTMLでそう決まっているから、という理由で詰まることは今後もありそうなので、選択肢の1つとして置いておこう
