The draggable kit gives you a full subcomponent structure that allows it to be used with almost any kit.
initial_items is a REQUIRED prop, which is the array of objects that contains data for the the draggable items.
draggable/draggable_container = This specifies the container within which items can be dropped.
draggable/draggable_item = This specifies the items that can be dragged and dropped. drag_id is a REQUIRED prop for draggable_item and must match the id on the items within initial_items.
<% initial_items = [ { id: "1", url: "https://unsplash.it/500/400/?image=633", }, { id: "2", url: "https://unsplash.it/500/400/?image=634", }, { id: "3", url: "https://unsplash.it/500/400/?image=637", }, ] %> <%= pb_rails("draggable", props: {initial_items: initial_items}) do %> <%= pb_rails("draggable/draggable_container") do %> <%= pb_rails("flex") do %> <% initial_items.each do |item| %> <%= pb_rails("draggable/draggable_item", props:{drag_id: item[:id]}) do %> <%= pb_rails("image", props: { alt: item[:id], size: "md", url: item[:url], margin: "xs" }) %> <% end %> <% end %> <% end %> <% end %> <% end %>
For a simplified version of the Draggable API for the List kit, you can do the following:
The List kit is optimized to work with the draggable kit. To enable drag, use the enable_drag prop on List kit with an array of the included items AND drag_id prop on ListItems. You will also need to include the items prop containing your array of listed items for the Draggable API.
An additional optional boolean prop (set to true by default) of drag_handle is also available on ListItem kit to show the drag handle icon.
<% initial_items = [ { id: "31", name: "Philadelphia" }, { id: "32", name: "New Jersey" }, { id: "33", name: "Maryland" }, { id: "34", name: "Connecticut" }, ] %> <%= pb_rails("list", props: { enable_drag: true, items: initial_items }) do %> <% initial_items.each do |item| %> <%= pb_rails("list/item", props:{drag_id: item[:id]}) do %><%= item[:name] %><% end %> <% end %> <% end %>
For a simplified version of the Draggable API for the SelectableList kit, you can do the following:
The SelectableList kit is optimized to work with the draggable kit. To enable drag, use the enable_drag prop on SelectableList kit AND drag_id prop within the SelectableList kit prop. An additional optional boolean prop (set to true by default) of drag_handle is also available on SelectableList kit to show the drag handle icon.
<%= pb_rails("selectable_list", props: { enable_drag: true, variant: "radio", items: [ { drag_id: "41", text: "Task 1", input_options: { value: "1", name: "radio-name", } }, { drag_id: "42", text: "Task 2", checked: true, input_options: { value: "2", name: "radio-name", } }, { drag_id: "43", text: "Task 3", input_options: { value: "3", name: "radio-name", } }, { drag_id: "44", text: "Task 4", input_options: { value: "4", name: "radio-name", } } ] } ) %>
For a simplified version of the Draggable API for the Card kit, you can do the following:
Use the draggable kit and manage state as shown.
draggable/draggable_container kit creates the container within which the cards can be dragged and dropped.
The Card kit is optimized to work with the draggable kit. To enable drag, use the draggable_item and drag_id props on the Card kit as shown. An additional optional boolean prop (set to true by default) of drag_handle is also available to show the drag handle icon.
<% initial_items = [ { id: "21", name: "Joe Black" }, { id: "22", name: "Nancy White" }, { id: "23", name: "Bill Green" }, ] %> <%= pb_rails("draggable", props: {initial_items: initial_items}) do %> <%= pb_rails("draggable/draggable_container") do %> <% initial_items.each do |item| %> <%= pb_rails("card", props: {highlight: {position: "side", color:"primary"}, margin_bottom: "xs", padding: "xs", drag_id: item[:id], draggable_item: true }) do %> <%= pb_rails("flex", props:{align_items: "stretch", flex_direction:"column"}) do %> <%= pb_rails("flex", props:{gap: "xs"}) do %> <%= pb_rails("title", props: { text: item[:name], tag: "h4", size: 4 }) %> <%= pb_rails("badge", props: {text:"35-12345" ,variant: "primary"}) %> <% end %> <%= pb_rails("caption", props: { size: "xs", text: "8:00A • Township Name • 90210" }) %> <%= pb_rails("flex", props:{gap: "xxs", spacing:"between"}) do %> <%= pb_rails("flex", props:{gap: "xxs"}) do %> <%= pb_rails("caption", props: { size: "xs" , color: "error" }) do %> <%= pb_rails("icon", props: { icon: "house-circle-exclamation", fixed_width: true }) %> <% end %> <%= pb_rails("caption", props: { size: "xs" , color: "success" }) do %> <%= pb_rails("icon", props: { icon: "file-circle-check", fixed_width: true }) %> <% end %> <% end %> <%= pb_rails("flex") do %> <%= pb_rails("badge", props: {text:"Schedule QA" ,variant: "warning", rounded: true}) %> <%= pb_rails("badge", props: {text:"Flex" ,variant: "primary", rounded: true}) %> <%= pb_rails("badge", props: {text:"R99" ,variant: "primary", rounded: true}) %> <% end %> <% end %> <% end %> <% end %> <% end %> <% end %> <% end %>
| id | name | task number |
|---|---|---|
| 1 |
Terry Miles
| Task 1 |
| 2 |
Sophia Miles
| Task 2 |
| 3 |
Alice Jones
| Task 3 |
| 4 |
Mike James
| Task 4 |
| 5 |
James Guy
| Task 5 |
The draggable kit can also be used in conjunction with the table kit to create draggable table rows. To do this:
draggable_container prop on the table/table_body to designate it as the Draggable Containerdraggable_item prop on the table/table_row to designate it as the Draggable Item. Make sure to also pass id to the drag_id prop here. <% initial_items = [ { id: "1", title: "Task 1", assignee_name: "Terry Miles", assignee_img: "https://randomuser.me/api/portraits/men/44.jpg", }, { id: "2", title: "Task 2", assignee_name: "Sophia Miles", assignee_img: "https://randomuser.me/api/portraits/women/8.jpg", }, { id: "3", title: "Task 3", assignee_name: "Alice Jones", assignee_img: "https://randomuser.me/api/portraits/women/10.jpg", }, { id: "4", title: "Task 4", assignee_name: "Mike James", assignee_img: "https://randomuser.me/api/portraits/men/8.jpg", }, { id: "5", title: "Task 5", assignee_name: "James Guy", assignee_img: "https://randomuser.me/api/portraits/men/18.jpg", } ] %> <%= pb_rails("draggable", props: {initial_items: initial_items}) do %> <%= pb_rails("table", props: { size: "sm", responsive:"none" }) do %> <%= pb_rails("table/table_head") do %> <%= pb_rails("table/table_row") do %> <%= pb_rails("table/table_header", props: { text: "id"}) %> <%= pb_rails("table/table_header", props: { text: "name"}) %> <%= pb_rails("table/table_header", props: { text: "task number"}) %> <% end %> <% end %> <%= pb_rails("table/table_body", props: {draggable_container: true}) do %> <% initial_items.each do |item| %> <%= pb_rails("table/table_row", props:{drag_id: item[:id], draggable_item: true}) do %> <%= pb_rails("table/table_cell", props: { text: item[:id]}) %> <%= pb_rails("table/table_cell") do %> <%= pb_rails("flex", props:{align:"center"}) do %> <%= pb_rails("avatar", props: {size: "xs", image_url: item[:assignee_img]}) %> <%= pb_rails("body", props: {text: item[:assignee_name], padding_left:"sm"}) %> <% end %> <% end %> <%= pb_rails("table/table_cell", props: { text: item[:title]}) %> <% end %> <% end %> <% end %> <% end %> <% end %>
The Draggable kit lets you customize the style of drop zones that appear when dragging an item.
By default, drop zones are in the "ghost" style, but you can also choose from "shadow," "outline," and "line."
When using the "line" type, make sure to set the appropriate direction attribute on the draggable/draggable_container component based on the orientation of your draggable view: "vertical" or "horizontal." Note that the direction attribute only applies to the "line" type and does not affect other drop zone styles. For more on the "line" style in particular, check out the Draggable Drop Zones Line doc example.
<% data_shadow = [ { id: "51", text: "Task 1" }, { id: "52", text: "Task 2" }, { id: "53", text: "Task 3" } ] %> <% data_outline = [ { id: "61", text: "Task 1" }, { id: "62", text: "Task 2" }, { id: "63", text: "Task 3" } ] %> <% data_line = [ { id: "71", text: "Task 1" }, { id: "72", text: "Task 2" }, { id: "73", text: "Task 3" } ] %> <%= pb_rails("flex", props: { justify: "between" }) do %> <%= pb_rails("flex/flex_item", props: { margin_right: "xl" }) do %> <%= pb_rails("draggable", props: { drop_zone_type: "shadow", initial_items: data_shadow }) do %> <%= pb_rails("caption", props: { margin_bottom: "xs", text: "Shadow", text_align: "center" }) %> <%= pb_rails("draggable/draggable_container", props: { html_options: { style: { width: "200px" } } }) do %> <% data_shadow.each do |item| %> <%= pb_rails("card", props: { drag_id: item[:id], draggable_item: true, margin_bottom: "xs", padding: "xs", padding_right: "xl" }) do %> <%= pb_rails("flex", props: { align_items: "stretch", flex_direction: "column" }) do %> <%= pb_rails("body", props: { text: item[:text] }) %> <% end %> <% end %> <% end %> <% end %> <% end %> <% end %> <%= pb_rails("flex/flex_item", props: { margin_right: "xl" }) do %> <%= pb_rails("draggable", props: { drop_zone_type: "outline", initial_items: data_outline }) do %> <%= pb_rails("caption", props: { margin_bottom: "xs", text: "Outline", text_align: "center" }) %> <%= pb_rails("draggable/draggable_container", props: { html_options: { style: { width: "200px" } } }) do %> <% data_outline.each do |item| %> <%= pb_rails("card", props: { drag_id: item[:id], draggable_item: true, margin_bottom: "xs", padding: "xs", padding_right: "xl" }) do %> <%= pb_rails("flex", props: { align_items: "stretch", flex_direction: "column" }) do %> <%= pb_rails("body", props: { text: item[:text] }) %> <% end %> <% end %> <% end %> <% end %> <% end %> <% end %> <%= pb_rails("flex/flex_item", props: { margin_right: "xl" }) do %> <%= pb_rails("draggable", props: { drop_zone_type: "line", initial_items: data_line }) do %> <%= pb_rails("caption", props: { margin_bottom: "xs", text: "Line", text_align: "center" }) %> <%= pb_rails("draggable/draggable_container", props: { drop_zone_direction: "vertical", html_options: { style: { width: "200px" } } }) do %> <% data_line.each do |item| %> <%= pb_rails("card", props: { drag_id: item[:id], draggable_item: true, margin_bottom: "xs", padding: "xs", padding_right: "xl", drop_zone_line_color: "primary" }) do %> <%= pb_rails("flex", props: { align_items: "stretch", flex_direction: "column" }) do %> <%= pb_rails("body", props: { text: item[:text] }) %> <% end %> <% end %> <% end %> <% end %> <% end %> <% end %> <% end %>
The default color for Draggable kit drop zones is "neutral", with "primary" or "purple" as additional options.
<% initial_items = [ { id: "141", url: "https://unsplash.it/500/400/?image=633", }, { id: "142", url: "https://unsplash.it/500/400/?image=634", }, { id: "143", url: "https://unsplash.it/500/400/?image=637", }, ] %> <% next_init_items = [ { id: "151", url: "https://unsplash.it/500/400/?image=633", }, { id: "152", url: "https://unsplash.it/500/400/?image=634", }, { id: "153", url: "https://unsplash.it/500/400/?image=637", }, ] %> <%= pb_rails("draggable", props: {initial_items: initial_items, drop_zone_type: "shadow", drop_zone_color: "primary"}) do %> <%= pb_rails("draggable/draggable_container") do %> <%= pb_rails("flex", props: { gap: "sm" }) do %> <% initial_items.each do |item| %> <%= pb_rails("draggable/draggable_item", props:{drag_id: item[:id]}) do %> <%= pb_rails("image", props: { alt: item[:id], size: "md", url: item[:url] }) %> <% end %> <% end %> <% end %> <% end %> <% end %> <br/> <%= pb_rails("draggable", props: {initial_items: next_init_items, drop_zone_type: "outline", drop_zone_color: "purple"}) do %> <%= pb_rails("draggable/draggable_container") do %> <%= pb_rails("flex", props: { gap: "sm" }) do %> <% initial_items.each do |item| %> <%= pb_rails("draggable/draggable_item", props:{drag_id: item[:id]}) do %> <%= pb_rails("image", props: { alt: item[:id], size: "md", url: item[:url] }) %> <% end %> <% end %> <% end %> <% end %> <% end %>
When using the "line" style, make sure to set the appropriate direction attribute within the drop_zone_direction prop on the draggable/draggable_container component based on the orientation of your draggable view: "vertical" or "horizontal." Note that the direction attribute only applies to the "line" style and does not affect other drop zone styles. Also, set the drop_zone_line_color prop on the draggable/draggable_item component to "primary" or "purple".
The length of the line is calculated based off of the width (for "vertical") or height (for "horizontal") of the parent container holding the draggable items.
Additionally, if the parent container of the draggable/draggable/draggable_container (or a subcontainer within) does not have a set height (for "vertical") or width (for "horizontal"), like the Draggable Drop Zones doc example does, elements on the page may jump up (for "vertical") or to the left (for "horizontal") when an item is actively being dragged. To prevent this, give a parent element a fixed height (for "vertical") or width (for "horizontal") as demonstrated in this doc example.
<% initial_items = [ { id: "211", url: "https://unsplash.it/500/400/?image=633", }, { id: "212", url: "https://unsplash.it/500/400/?image=634", }, { id: "213", url: "https://unsplash.it/500/400/?image=637", }, ] %> <% next_init_items = [ { id: "2111", url: "https://unsplash.it/500/400/?image=633", }, { id: "2112", url: "https://unsplash.it/500/400/?image=634", }, { id: "2113", url: "https://unsplash.it/500/400/?image=637", }, ] %> <%= pb_rails("draggable", props: {initial_items: initial_items, drop_zone_type: "line"}) do %> <%= pb_rails("draggable/draggable_container", props: { drop_zone_direction: "vertical" }) do %> <%= pb_rails("flex", props: { gap: "sm", orientation: "column", height: "367px" }) do %> <% initial_items.each do |item| %> <%= pb_rails("draggable/draggable_item", props:{drag_id: item[:id], drop_zone_line_color: "purple"}) do %> <%= pb_rails("image", props: { alt: item[:id], size: "md", url: item[:url] }) %> <% end %> <% end %> <% end %> <% end %> <% end %> <br/> <%= pb_rails("draggable", props: {initial_items: next_init_items, drop_zone_type: "line"}) do %> <%= pb_rails("draggable/draggable_container", props: { drop_zone_direction: "horizontal" }) do %> <%= pb_rails("flex", props: { gap: "sm", html_options: { style: "width: 332px;" } }) do %> <% initial_items.each do |item| %> <%= pb_rails("draggable/draggable_item", props:{drag_id: item[:id], drop_zone_line_color: "primary"}) do %> <%= pb_rails("image", props: { alt: item[:id], size: "md", url: item[:url] }) %> <% end %> <% end %> <% end %> <% end %> <% end %>
You can add drag event listeners for drag, dragend, dragenter, dragleave, dragover, dragstart, and drop.
<% initial_items = [ { id: "100", url: "https://unsplash.it/500/400/?image=638", }, { id: "200", url: "https://unsplash.it/500/400/?image=639", }, { id: "300", url: "https://unsplash.it/500/400/?image=640", }, ] %> <%= pb_rails("draggable", props: {initial_items: initial_items}) do %> <%= pb_rails("draggable/draggable_container") do %> <%= pb_rails("flex") do %> <% initial_items.each do |item| %> <%= pb_rails("draggable/draggable_item", props:{drag_id: item[:id]}) do %> <%= pb_rails("image", props: { alt: item[:id], size: "md", url: item[:url], margin: "xs" }) %> <% end %> <% end %> <% end %> <% end %> <% end %> <script> const itemIds = ["item_100", "item_200", "item_300"]; itemIds.forEach((id) => { const element = document.getElementById(id); if (element) { element.addEventListener("dragstart", (event) => { console.log(`${id} drag start!`); }); element.addEventListener("dragend", (event) => { console.log(`${id} drag end!`); }); } }); </script>
The Draggable kit can also be used to achieve more complex, multiple container functionality as shown here. This complex usage requires the full subcomponent structure.
<% containers = [ "To Do", "In Progress", "Done" ] %> <% items_data = [ { id: "11", container: "To Do", title: "Task 1", description: "Bug fixes", assignee_name: "Terry Miles", assignee_img: "https://randomuser.me/api/portraits/men/44.jpg", }, { id: "12", container: "To Do", title: "Task 2", description: "Documentation", assignee_name: "Sophia Miles", assignee_img: "https://randomuser.me/api/portraits/women/8.jpg", }, { id: "13", container: "In Progress", title: "Task 3", description: "Add a variant", assignee_name: "Alice Jones", assignee_img: "https://randomuser.me/api/portraits/women/10.jpg", }, { id: "14", container: "To Do", title: "Task 4", description: "Add jest tests", assignee_name: "Mike James", assignee_img: "https://randomuser.me/api/portraits/men/8.jpg", }, { id: "15", container: "Done", title: "Task 5", description: "Alpha testing", assignee_name: "James Guy", assignee_img: "https://randomuser.me/api/portraits/men/18.jpg", }, { id: "16", container: "In Progress", title: "Task 6", description: "Release", assignee_name: "Sally Jones", assignee_img: "https://randomuser.me/api/portraits/women/28.jpg", }, ] %> <%= pb_rails("draggable", props: { initial_items: items_data }) do %> <%= pb_rails("flex", props: { justify_content: "center" }) do %> <% containers.each do |container| %> <%= pb_rails("draggable/draggable_container", props: { container: container, width: "xs", padding: "sm", data: { container: container } }) do %> <%= pb_rails("caption", props: { text_align: "center" }) do %><%= container %><% end %> <%= pb_rails("flex", props: {align_items: "stretch", orientation: "column"}) do %> <% items_data.select { |item| item[:container] == container }.each do |item| %> <%= pb_rails("draggable/draggable_item", props: { container: container, drag_id: item[:id] }) do %> <%= pb_rails("card", props: { margin_bottom: "sm", padding: "sm"}) do %> <%= pb_rails("flex", props: { justify: "between" }) do %> <%= pb_rails("flex/flex_item") do %> <%= pb_rails("flex") do %> <%= pb_rails("avatar", props: { image_url: item[:assignee_img], name: item[:assignee_name], size: "xxs" }) %> <%= pb_rails("title", props: { padding_left: "xs", size: 4, text: item[:title] }) %> <% end %> <% end %> <% end %> <%= pb_rails("body", props: { padding_top: "xs", text: item[:description] }) %> <% end %> <% end %> <% end %> <% end %> <% end %> <% end %> <% end %> <% end %>
| Props | Type | Values |
|---|---|---|
align_content |
enum | responsive
|
start
end
center
spaceBetween
spaceAround
spaceEvenly
|
align_items |
enum | responsive
|
start
end
center
|
border_radius |
enum
|
none
xs
sm
md
lg
xl
rounded
|
cursor |
enum
|
auto
default
none
contextMenu
help
pointer
progress
wait
cell
|
dark |
boolean
|
true
false
|
flex |
enum | responsive
|
auto
initial
0
1
2
3
4
5
6
7
8
9
10
11
12
none
|
flex_direction |
enum | responsive
|
row
column
rowReverse
columnReverse
|
flex_wrap |
enum | responsive
|
wrap
nowrap
wrapReverse
|
justify_content |
enum | responsive
|
start
end
center
spaceBetween
spaceAround
spaceEvenly
|
line_height |
enum
|
loosest
looser
loose
normal
tight
tighter
tightest
|
margin_right |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_left |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_top |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_bottom |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_x |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_y |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin |
array
|
none
xxs
xs
sm
md
lg
xl
|
width |
string
|
|
min_width |
string
|
|
max_width |
string
|
|
gap |
string | responsive
|
|
column_gap |
string | responsive
|
|
row_gap |
string | responsive
|
|
number_spacing |
enum
|
tabular
|
order |
enum | responsive
|
none
first
1
2
3
4
5
6
7
8
9
10
11
12
|
overflow_x |
enum
|
scroll
visible
hidden
auto
|
overflow_y |
enum
|
scroll
visible
hidden
auto
|
overflow |
enum
|
scroll
visible
hidden
auto
|
padding_right |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_left |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_top |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_bottom |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_x |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_y |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding |
array
|
none
xxs
xs
sm
md
lg
xl
|
position |
enum
|
relative
absolute
fixed
sticky
static
|
shadow |
enum
|
none
deep
deeper
deepest
|
text_align |
enum | responsive
|
start
end
left
right
center
justify
justifyAll
matchParent
|
truncate |
enum
|
none
1
2
3
4
5
|
vertical_align |
enum | responsive
|
baseline
super
top
middle
bottom
sub
text-top
text-bottom
|
z_index |
enum | responsive
|
1
2
3
4
5
6
7
8
9
10
max
|
top |
enum | object
|
xxs
xs
sm
md
lg
xl
xxl
|
inset |
boolean
|
true
false
|
right |
enum | object
|
xxs
xs
sm
md
lg
xl
xxl
|
bottom |
enum | object
|
xxs
xs
sm
md
lg
xl
xxl
|
left |
enum | object
|
xxs
xs
sm
md
lg
xl
xxl
|
height |
string
|
|
max_height |
string
|
|
min_height |
string
|
|
hover |
object
|
|
group_hover |
boolean
|
true
false
|
| Props | Type | Values | Default |
|---|---|---|---|
drop_zone |
enum
|
ghost
outline
shadow
line
|
|
drop_zone_color |
enum
|
primary
neutral
purple
|
neutral
|
initial_items |
array
|
||
drop_zone_type |
enum
|
ghost
shadow
outline
line
|
ghost
|