Tucano v0.37.2

Button group

Two roles in the same box. Joined, it turns actions that belong together into one block instead of three loose buttons on the line. With is-segmented, it dresses the <input> as a button — picking one option out of a few, with the look of the segmented tabs. Class only: no JavaScript, and the value still belongs to the native <input>.

Period: day

Examples

The same .tuc-btn-group on the outside; inside, either buttons or labels with an <input> in them.

One option out of a few

It is type="radio": the browser clears the previous one, and the arrow keys move through the group.

Several at once

Switch to type="checkbox" and each button turns on and off on its own.

Joined actions

Without is-segmented, the buttons share the border and only the ends are rounded. Any variant works.

Small, next to a field

is-sm on the buttons matches the height of an is-sm field; the corner follows.

Full width

is-block takes the whole line and splits it evenly — the way to go on a phone.

With label and hint

In a form it is a field like any other: .tuc-label above, .tuc-hint below.

Tax regime

Changes how the tax on the invoice is worked out.

How to use

For the choice, the <input> goes inside the <label class="tuc-btn">, as a direct child: it is what the CSS reads to know which one is checked.

&lt;div class="tuc-btn-group is-segmented" role="group" aria-label="Period"&gt;
  &lt;label class="tuc-btn"&gt;
    &lt;input type="radio" class="tuc-btn__input" name="period" value="day" checked&gt; Day
  &lt;/label&gt;
  &lt;label class="tuc-btn"&gt;
    &lt;input type="radio" class="tuc-btn__input" name="period" value="week"&gt; Week
  &lt;/label&gt;
&lt;/div&gt;

&lt;div class="tuc-btn-group" role="group" aria-label="Contract actions"&gt;
  &lt;button type="button" class="tuc-btn is-outline"&gt;Edit&lt;/button&gt;
  &lt;button type="button" class="tuc-btn is-outline"&gt;Duplicate&lt;/button&gt;
&lt;/div&gt;

role="group" with an aria-label (or aria-labelledby pointing at the label) is what makes the screen reader announce what the row is about. In a form, a <fieldset> with a <legend> works too — just do not put the legend inside the group, which is a row of buttons.

In a Django form

No new widget: it is the usual RadioSelect, with the class in attrs and the field looped over in the template.

period = forms.ChoiceField(
    choices=[('day', 'Day'), ('week', 'Week'), ('month', 'Month')],
    widget=forms.RadioSelect(attrs={'class': 'tuc-btn__input'}),
)
&lt;div class="tuc-btn-group is-segmented" role="group" aria-label="{{ form.period.label }}"&gt;
  {% for radio in form.period %}
    &lt;label class="tuc-btn"&gt;{{ radio.tag }} {{ radio.choice_label }}&lt;/label&gt;
  {% endfor %}
&lt;/div&gt;

Looks like a tab, but is not one

A segmented tab changes what is on the screen and never reaches the server. The button group is a field: it has name and value, it goes in the POST and it takes required. If the choice travels with the form, it belongs here; if it only swaps a panel, it belongs there.

Up to about four options, and short ones

They all stay visible side by side: with many of them, or with long text, the row bursts the line on a phone. Past that, use the select or the options in a list — which are also the right call when each option needs an explanation under it.

Keyboard and accessibility

All native. In the choice, what takes the focus is the <input> — invisible, but present: it has zero opacity rather than being hidden, precisely so it stays focusable and announced. The focus ring shows on the button around it.

KeyWhereAction
TabRadio groupLands on the checked option and then leaves — the whole group is a single stop
← → ↑ ↓Focused radioMoves through the options and checks the one it lands on
TabCheckboxes and buttonsEach is its own stop, because each acts on its own
SpaceFocused checkboxTurns it on and off
Enter SpaceAction buttonActivates it

Classes

CSS only. The box is the segmented tab's, on purpose: both have to line up with the fields on the row, which is why the border plus the padding add up to exactly --tuc-control-height.

ClassWhat for
tuc-btn-groupThe row. On its own, it joins the buttons into a single block
is-segmentedThe recessed box of the segmented tabs, for choice as buttons
is-blockTakes the whole line, split evenly
tuc-btn__inputThe <input> inside the label: invisible, focusable and still the owner of the value
tuc-btn and its variantsEach item in the group — is-outline, is-primary, is-sm, is-icon