Skip to main content

telegram_webapp_sdk/yew/
back_button.rs

1// SPDX-FileCopyrightText: 2025-2026 RAprogramm <andrey.rozanov.vl@gmail.com>
2// SPDX-License-Identifier: MIT
3
4use std::cell::RefCell;
5
6use yew::prelude::{Callback, Html, Properties, function_component, html, use_effect_with};
7
8use crate::{
9    logger,
10    webapp::{EventHandle, TelegramWebApp}
11};
12
13thread_local! {
14    static BACK_BUTTON_HANDLE: RefCell<Option<EventHandle<dyn FnMut()>>> =
15        const { RefCell::new(None) };
16}
17
18/// Props for [`BackButton`].
19#[derive(Properties, PartialEq)]
20pub struct BackButtonProps {
21    /// Whether the native back button is shown.
22    #[prop_or(true)]
23    pub visible:  bool,
24    /// Click handler.
25    #[prop_or_default]
26    pub on_click: Callback<()>
27}
28
29/// Yew component for the native back button.
30///
31/// Shows or hides `WebApp.BackButton` based on the `visible` prop and routes
32/// clicks through the `on_click` callback. The subscription is removed and the
33/// button hidden on unmount.
34///
35/// # Examples
36/// ```no_run
37/// use telegram_webapp_sdk::yew::BackButton;
38/// use yew::prelude::*;
39///
40/// #[function_component(App)]
41/// fn app() -> Html {
42///     let cb = Callback::from(|_| {
43///         web_sys::console::log_1(&"back".into());
44///     });
45///     html! { <BackButton visible={true} on_click={cb} /> }
46/// }
47/// ```
48#[function_component(BackButton)]
49pub fn back_button(props: &BackButtonProps) -> Html {
50    let visible = props.visible;
51    let on_click = props.on_click.clone();
52
53    use_effect_with(visible, move |&v| {
54        if let Some(app) = TelegramWebApp::instance() {
55            let result = if v {
56                app.show_back_button()
57            } else {
58                app.hide_back_button()
59            };
60            if let Err(err) = result {
61                logger::error(&format!("BackButton visibility toggle failed: {err:?}"));
62            }
63        }
64        || ()
65    });
66
67    use_effect_with((), move |()| {
68        if let Some(app) = TelegramWebApp::instance() {
69            match app.set_back_button_callback(move || on_click.emit(())) {
70                Ok(handle) => BACK_BUTTON_HANDLE.with(|c| {
71                    *c.borrow_mut() = Some(handle);
72                }),
73                Err(err) => logger::error(&format!("set_back_button_callback failed: {err:?}"))
74            }
75        }
76        || {
77            if let Some(app) = TelegramWebApp::instance() {
78                BACK_BUTTON_HANDLE.with(|c| {
79                    if let Some(handle) = c.borrow_mut().take()
80                        && let Err(err) = app.remove_back_button_callback(handle)
81                    {
82                        logger::error(&format!("remove_back_button_callback failed: {err:?}"));
83                    }
84                });
85                if let Err(err) = app.hide_back_button() {
86                    logger::error(&format!("hide_back_button failed: {err:?}"));
87                }
88            }
89        }
90    });
91
92    html! {}
93}