scroll_area.rs
1 //! Defines the [`ScrollArea`] component for creating scrollable areas with customizable scrollbars. 2 3 use dioxus::prelude::*; 4 5 /// The props for the [`ScrollArea`] component. 6 #[derive(Props, Clone, PartialEq)] 7 pub struct ScrollAreaProps { 8 /// The scroll direction. 9 #[props(default)] 10 pub direction: ReadSignal<ScrollDirection>, 11 12 /// Whether the scrollbars should be always visible. 13 #[props(default)] 14 pub always_show_scrollbars: ReadSignal<bool>, 15 16 /// The scroll type. 17 #[props(default)] 18 pub scroll_type: ReadSignal<ScrollType>, 19 20 /// Additional attributes to apply to the scroll area element. 21 #[props(extends = GlobalAttributes)] 22 pub attributes: Vec<Attribute>, 23 /// The children of the scroll area component. 24 pub children: Element, 25 } 26 27 /// The direction in which scrolling is allowed. 28 #[derive(Clone, Copy, PartialEq, Default)] 29 pub enum ScrollDirection { 30 /// Allow vertical scrolling only. 31 Vertical, 32 /// Allow horizontal scrolling only. 33 Horizontal, 34 /// Allow scrolling in both directions. 35 #[default] 36 Both, 37 } 38 39 /// The type of scrolling behavior. 40 #[derive(Clone, Copy, PartialEq, Default)] 41 pub enum ScrollType { 42 /// Browser default scrolling. 43 #[default] 44 Auto, 45 /// Always show scrollbars. 46 Always, 47 /// Hide scrollbars but enable scrolling. 48 Hidden, 49 } 50 51 /// # ScrollArea 52 /// 53 /// The `ScrollArea` component creates a scrollable area. If you don't 54 /// have any focusable content within the scroll area, you should make the 55 /// scroll area focusable by adding a `tabindex` attribute. 56 /// 57 /// ## Example 58 /// 59 /// ```rust 60 /// use dioxus::prelude::*; 61 /// use dioxus_primitives::scroll_area::{ScrollArea, ScrollDirection}; 62 /// #[component] 63 /// fn Demo() -> Element { 64 /// rsx! { 65 /// ScrollArea { 66 /// width: "10em", 67 /// height: "10em", 68 /// direction: ScrollDirection::Vertical, 69 /// tabindex: "0", 70 /// div { class: "scroll-content", 71 /// for i in 1..=20 { 72 /// p { 73 /// "Scrollable content item {i}" 74 /// } 75 /// } 76 /// } 77 /// } 78 /// } 79 /// } 80 /// ``` 81 /// 82 /// ## Styling 83 /// 84 /// The [`ScrollArea`] component defines the following data attributes you can use to control styling: 85 /// - `data-scroll-direction`: Indicates the scroll direction. Values are `vertical`, `horizontal`, or `both`. 86 #[component] 87 pub fn ScrollArea(props: ScrollAreaProps) -> Element { 88 let direction = props.direction; 89 let scroll_type = props.scroll_type; 90 let always_show = props.always_show_scrollbars; 91 92 let (overflow_x, overflow_y, scrollbar_width) = match scroll_type() { 93 ScrollType::Auto => match direction() { 94 ScrollDirection::Vertical => (Some("hidden"), Some("auto"), None), 95 ScrollDirection::Horizontal => (Some("auto"), Some("hidden"), None), 96 ScrollDirection::Both => (Some("auto"), Some("auto"), None), 97 }, 98 ScrollType::Always => match direction() { 99 ScrollDirection::Vertical => (Some("hidden"), Some("scroll"), None), 100 ScrollDirection::Horizontal => (Some("scroll"), Some("hidden"), None), 101 ScrollDirection::Both => (Some("scroll"), Some("scroll"), None), 102 }, 103 ScrollType::Hidden => match direction() { 104 ScrollDirection::Vertical => (Some("hidden"), Some("scroll"), Some("none")), 105 ScrollDirection::Horizontal => (Some("scroll"), Some("hidden"), Some("none")), 106 ScrollDirection::Both => (Some("scroll"), Some("scroll"), Some("none")), 107 }, 108 }; 109 110 let visibility_class = use_memo(move || { 111 if always_show() { 112 "scroll-area-always-show" 113 } else { 114 "scroll-area-auto-hide" 115 } 116 }); 117 118 rsx! { 119 div { 120 class: "{visibility_class}", 121 overflow_x, 122 overflow_y, 123 "scrollbar-width": scrollbar_width, 124 "data-scroll-direction": match direction() { 125 ScrollDirection::Vertical => "vertical", 126 ScrollDirection::Horizontal => "horizontal", 127 ScrollDirection::Both => "both", 128 }, 129 ..props.attributes, 130 131 {props.children} 132 } 133 } 134 }