Skip to content
This repository was archived by the owner on Sep 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions docs/src/content/docs/components/radio_button.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

---
<!-- Copyright © SixtyFPS GmbH <info@slint.dev> ; SPDX-License-Identifier: MIT -->
title: RadioButton
description: RadioButton API.
---

import CodeSnippetMD from '/src/components/CodeSnippetMD.astro';
import SlintProperty from '/src/components/SlintProperty.astro';

<CodeSnippetMD imagePath="/src/assets/generated/radiobutton.png" scale="3" imageWidth="300" imageHeight="200" imageAlt="" needsBackground="true">
```slint
import { RadioButton } from "material.slint";
export component Example inherits Window {
width: 200px;
height: 100px;
RadioButton {
checked: true;
}
}
```
</CodeSnippetMD>

`RadioButton`s let people select one option from a set of options.

## Properties

### checked
<SlintProperty propName="checked" typeName="bool" propertyVisibility="in">
Whether the radiobutton is checked.
</SlintProperty>

### enabled
<SlintProperty propName="enabled" typeName="bool" defaultValue="true">
Whether the radiobutton is enabled and can be interacted with.
</SlintProperty>

## Callbacks

### clicked()
Invoked when the radiobutton is clicked.
21 changes: 20 additions & 1 deletion examples/gallery/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use std::rc::Rc;

use slint::{Color, ModelExt, VecModel};
use slint::{Color, Model, ModelExt, VecModel};
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;

Expand Down Expand Up @@ -66,6 +66,25 @@ fn navigation_view(ui: &MainWindow) {
);
}
});

let radio_buttons = VecModel::from_slice(&[true, false, false]);

adapter.on_radio_button_clicked({
let radio_buttons = radio_buttons.clone();

move |index| {
for r in 0..radio_buttons.row_count() {
if r == index as usize {
radio_buttons.set_row_data(r, true);
continue;
}

radio_buttons.set_row_data(r, false);
}
}
});

adapter.set_radio_buttons(radio_buttons.into());
}

fn color_item(name: &str, red: u8, green: u8, blue: u8, ui: &MainWindow) -> ListItem {
Expand Down
43 changes: 42 additions & 1 deletion examples/gallery/ui/views/navigation_view.slint
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ import {
TimePicker,
Switch,
Slider,
TextField
TextField,
RadioButtonTile
} from "../../../../material.slint";

import { Group } from "../components/group.slint";
Expand All @@ -40,8 +41,10 @@ import { FilledIcons, OutlinedIcons } from "../icons.slint";

export global NavigationViewAdapter {
in_out property <[ListItem]> search_items;
in property <[bool]> radio_buttons: [ true, false, false ];

callback search(text: string);
callback radio_button_clicked(index: int);
}

export component NavigationView {
Expand Down Expand Up @@ -327,6 +330,44 @@ export component NavigationView {
}
}

ComponentCard {
title: "RadioButtons";

Vertical {
RadioButtonTile {
text: "Option 1";
checked: NavigationViewAdapter.radio_buttons[0];

radio_button_clicked => {
NavigationViewAdapter.radio_button_clicked(0);
}
}

RadioButtonTile {
text: "Option 2";
checked: NavigationViewAdapter.radio_buttons[1];

radio_button_clicked => {
NavigationViewAdapter.radio_button_clicked(1);
}
}

RadioButtonTile {
text: "Option 3";
checked: NavigationViewAdapter.radio_buttons[2];

radio_button_clicked => {
NavigationViewAdapter.radio_button_clicked(2);
}
}

RadioButtonTile {
text: "Option 4";
enabled: false;
}
}
}

ComponentCard {
title: "Chips";

Expand Down
1 change: 1 addition & 0 deletions material.slint
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export { NavigationBar } from "./ui/components/navigation_bar.slint";
export { NavigationDrawer, ModalNavigationDrawer } from "./ui/components/navigation_drawer.slint";
export { NavigationRail } from "./ui/components/navigation_rail.slint";
export { CircularProgressIndicator, LinearProgressIndicator } from "./ui/components/progress_indicator.slint";
export { RadioButton, RadioButtonTile } from "./ui/components/radio_button.slint";
export { SearchBar } from "./ui/components/search_bar.slint";
export { ScrollView } from "./ui/components/scroll_view.slint";
export { Slider } from "./ui/components/slider.slint";
Expand Down
1 change: 1 addition & 0 deletions ui/components/check_box.slint
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export component CheckBox {
accessible-checked <=> root.checked;
accessible-role: checkbox;
accessible-action-default => { state_area.clicked(); }
forward_focus: state_area;

state_area := StateLayerArea {
width: 100%;
Expand Down
99 changes: 99 additions & 0 deletions ui/components/radio_button.slint
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT

import { MaterialStyleMetrics } from "../styling/material_style_metrics.slint";
import { MaterialPalette } from "../styling/material_palette.slint";
import { Animations } from "../styling/animations.slint";
import { StateLayerArea } from "./state_layer.slint";
import { ListTile } from "./list.slint";
import { ListView } from "./list_view.slint";

export component RadioButton {
in property <bool> checked;
in property <bool> enabled;

callback clicked();

min_width: MaterialStyleMetrics.size_40;
min_height: self.min_width;
accessible-enabled: root.enabled;
accessible-checkable: true;
accessible-checked <=> root.checked;
accessible-role: checkbox;
accessible-action-default => { state_area.clicked(); }
forward_focus: state_area;

state_area := StateLayerArea {
width: 100%;
height: 100%;
border_radius: max(self.width, self.height) / 2;
color: MaterialPalette.on_surface;

border := Rectangle {
width: MaterialStyleMetrics.size_20;
height: self.width;
border_radius: max(self.width, self.height) / 2;
border_color: MaterialPalette.on_surface_variant;
border_width: MaterialStyleMetrics.size_2;

indicator := Rectangle {
width: parent.width / 2;
height: self.width;
border_radius: max(self.width, self.height) / 2;
background: MaterialPalette.primary;
opacity: !root.checked ? 0 : 1;

animate opacity {
duration: Animations.opacity_duration;
easing: Animations.opacity_easing;
}
}

animate border_color {
duration: Animations.opacity_duration;
easing: Animations.opacity_easing;
}
}

clicked => {
root.clicked();
}
}

states [
disabled when !root.enabled : {
border.border_color: MaterialPalette.on_surface;
border.opacity: MaterialPalette.disable_opacity;
indicator.background: MaterialPalette.on_surface;
indicator.opacity: root.checked ? MaterialPalette.disable_opacity : 0;
}
highlighted when !root.checked && (state_area.pressed || state_area.has_focus || state_area.has_hover) : {
border.border_color: MaterialPalette.on_surface;
}
checked when root.checked : {
border.border_color: MaterialPalette.primary;
}
]
}

export component RadioButtonTile inherits ListTile {
in_out property <bool> checked <=> radio_button.checked;

callback radio_button_clicked();

Rectangle {
horizontal_stretch: 0;

radio_button := RadioButton {
enabled: root.enabled;

clicked => {
root.radio_button_clicked();
}
}
}

clicked => {
radio_button.clicked();
}
}
1 change: 1 addition & 0 deletions ui/styling/material_style_metrics.slint
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export global MaterialStyleMetrics {
out property <length> size_8: 8px;
out property <length> size_16: 16px;
out property <length> size_18: 18px;
out property <length> size_20: 20px;
out property <length> size_24: 24px;
out property <length> size_30: 30px;
out property <length> size_32: 32px;
Expand Down