x
1
2
3
<form action="/slow_action" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" value="pgYUXY23HsE-LlMFjcSvKaZJheJLxA-CaoY_IIM1AlzJET1UIE3oXOzM62IfDh23ArtxtnAMp1DQRLK6rleCTQ" autocomplete="off" /> <button name="button" type="submit" class="btn btn--loading"><span>Click and wait</span></button></form>
1
2
3
<%= form_with(url: main_app.slow_action_path) do |form| %> <%= button_tag tag.span("Click and wait"), class: "btn btn--loading" %><% end %>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
.btn { --btn-background: var(--color-bg); --hover-color: oklch(from var(--btn-background) calc(l * .95) c h); align-items: center; background-color: var(--btn-background); block-size: var(--btn-block-size, auto); border-radius: var(--btn-radius, var(--rounded-md)); border: 1px solid var(--btn-border-color, var(--color-border)); box-shadow: var(--btn-box-shadow, var(--shadow-xs)); color: var(--btn-color, var(--color-text)); column-gap: var(--size-2); cursor: default; display: inline-flex; font-size: var(--btn-font-size, var(--text-sm)); font-weight: var(--btn-font-weight, var(--font-medium)); inline-size: var(--btn-inline-size, auto); justify-content: var(--btn-justify-content, center); padding: var(--btn-padding, .375rem 1rem); position: relative; text-align: var(--btn-text-align, center); white-space: nowrap; img:not([class]) { filter: var(--btn-icon-color, var(--color-filter-text)); } &:hover { background-color: var(--btn-hover-color, var(--hover-color)); } &:focus-visible { outline: var(--btn-outline-size, 2px) solid var(--color-selected-dark); } &:is(:disabled, [aria-disabled]) { opacity: var(--opacity-50); pointer-events: none; }}.btn--primary { --btn-background: var(--color-primary); --btn-border-color: transparent; --btn-color: var(--color-text-reversed); --btn-icon-color: var(--color-filter-text-reversed);}.btn--secondary { --btn-background: var(--color-secondary); --btn-border-color: transparent;}.btn--borderless { --btn-border-color: transparent; --btn-box-shadow: none;}.btn--positive { --btn-background: var(--color-positive); --btn-border-color: transparent; --btn-color: white; --btn-icon-color: invert(1);}.btn--negative { --btn-background: var(--color-negative); --btn-border-color: transparent; --btn-color: white; --btn-icon-color: invert(1);}.btn--plain { --btn-background: transparent; --btn-border-color: transparent; --btn-hover-color: transparent; --btn-padding: 0; --btn-box-shadow: none;}.btn--icon { --btn-padding: var(--size-2);}[aria-busy] .btn--loading:disabled { > * { visibility: hidden; } &::after { animation: spin 1s linear infinite; background-image: url("loader-circle.svg"); background-size: cover; block-size: var(--size-5); content: ""; filter: var(--btn-icon-color, var(--color-filter-text)); inline-size: var(--size-5); position: absolute; }}
Java Script is not required or multiple files are needed, check the notes.
Turbo adds aria-busy
to the form while the form request is in progress,
check here.