diff --git a/src/asset.rs b/src/asset.rs
index 2a929f9..0239eda 100644
--- a/src/asset.rs
+++ b/src/asset.rs
@@ -52,15 +52,12 @@ pub trait AssetRoutes {
 
 impl AssetRoutes for rocket::Rocket<Build> {
     fn mount_assets(self) -> Self {
-        self.mount(
-            "/",
-            routes![
-                crate::asset::htmx_script_route,
-                crate::asset::flowbite_css,
-                crate::asset::flowbite_js,
-                crate::asset::material_css,
-                crate::asset::material_font
-            ],
-        )
+        self.mount("/", routes![
+            crate::asset::htmx_script_route,
+            crate::asset::flowbite_css,
+            crate::asset::flowbite_js,
+            crate::asset::material_css,
+            crate::asset::material_font
+        ])
     }
 }
diff --git a/src/ui/components/appbar.rs b/src/ui/components/appbar.rs
index aaaf378..263bf15 100644
--- a/src/ui/components/appbar.rs
+++ b/src/ui/components/appbar.rs
@@ -1,5 +1,3 @@
-use maud::{Markup, Render};
-
 use crate::auth::User;
 
 use crate::ui::primitives::Optional;
diff --git a/src/ui/components/indicator.rs b/src/ui/components/indicator.rs
index bb22beb..cfff2ea 100644
--- a/src/ui/components/indicator.rs
+++ b/src/ui/components/indicator.rs
@@ -4,12 +4,14 @@ use crate::ui::{UIWidget, color::UIColor};
 
 use super::ColorCircle;
 
+#[allow(non_snake_case)]
 pub fn Indicator<C: UIColor + 'static>(color: C) -> PreEscaped<String> {
     html! {
         span class=(format!("flex w-3 h-3 me-3 bg-{} rounded-full", color.color_class())) {};
     }
 }
 
+#[allow(non_snake_case)]
 pub fn IndicatorLegend<C: UIColor + 'static>(color: C, legend: &str) -> PreEscaped<String> {
     html! {
         span class="flex items-center text-sm font-medium text-gray-900 dark:text-white me-3" {
@@ -19,6 +21,7 @@ pub fn IndicatorLegend<C: UIColor + 'static>(color: C, legend: &str) -> PreEscap
     }
 }
 
+#[allow(non_snake_case)]
 pub fn NumberIndicator<T: UIWidget + 'static>(on: T, amount: u32) -> PreEscaped<String> {
     html! {
             div class="relative items-center max-w-fit" {
@@ -28,6 +31,7 @@ pub fn NumberIndicator<T: UIWidget + 'static>(on: T, amount: u32) -> PreEscaped<
         }
 }
 
+#[allow(non_snake_case)]
 pub fn BadgeIndicator<C: UIColor + 'static + ColorCircle>(
     color: C,
     dark_color: C,
diff --git a/src/ui/components/mod.rs b/src/ui/components/mod.rs
index d3e5219..817e002 100644
--- a/src/ui/components/mod.rs
+++ b/src/ui/components/mod.rs
@@ -15,7 +15,7 @@ pub mod prelude {
     pub use super::appbar::AppBar;
     pub use super::avatar::{Avatar, AvatarStack};
     pub use super::htmx::{ClickToLoad, InfinityScroll, LazyLoad};
-    pub use super::icon::MaterialIcon;
+    pub use super::icon::{ColoredMaterialIcon, MaterialIcon};
     pub use super::indicator::{BadgeIndicator, Indicator, IndicatorLegend, NumberIndicator};
     pub use super::modal::{Modal, ModalCloseButton, ModalOpenButton};
     pub use super::overlay::{
@@ -31,6 +31,7 @@ pub mod prelude {
         Alignment, BottomNavigation, BottomNavigationTile, Classic, ClassicWidget, FetchToast,
         NavBar, Position, Shell, Toast,
     };
+    pub use super::timeline::{ActivityLog, ActivityLogElement, Timeline, TimelineElement};
     pub use super::{
         Accordion, Alert, Banner, Breadcrumb, Card, Carousel, CarouselMode, ColoredAlert,
         ColoredSpinner, CopyText, FetchAlert, FnKey, HelpIcon, HorizontalLine, IconStepper,
@@ -56,12 +57,14 @@ pub fn HorizontalLine() -> PreEscaped<String> {
     }
 }
 
+#[allow(non_snake_case)]
 pub fn FnKey(key: &str) -> PreEscaped<String> {
     html! {
         kbd class="px-2 py-1.5 text-xs font-semibold text-gray-800 bg-gray-100 border border-gray-200 rounded-lg dark:bg-gray-600 dark:text-gray-100 dark:border-gray-500" { (key) };
     }
 }
 
+#[allow(non_snake_case)]
 pub fn ColoredSpinner<T: UIColor + 'static>(color: T) -> PreEscaped<String> {
     let col = color.color_class();
     html! {
@@ -80,6 +83,7 @@ pub fn Spinner() -> PreEscaped<String> {
     ColoredSpinner(super::color::Blue::_600)
 }
 
+#[allow(non_snake_case)]
 pub fn CopyText(txt: &str) -> PreEscaped<String> {
     let id = uuid::Uuid::new_v4().to_string();
 
@@ -739,12 +743,14 @@ impl UIWidget for StepperWidget {
 
 pub struct TabWidget {
     pub content: Vec<(PreEscaped<String>, String, Box<dyn UIWidget>)>,
+    pub active: String,
 }
 
 #[allow(non_snake_case)]
 pub fn Tabs() -> TabWidget {
     TabWidget {
         content: Vec::new(),
+        active: String::new(),
     }
 }
 
@@ -759,6 +765,11 @@ impl TabWidget {
             .push((tab.render(), id.to_string(), Box::new(body)));
         self
     }
+
+    pub fn active(mut self, id: &str) -> Self {
+        self.active = id.to_string();
+        self
+    }
 }
 
 impl Render for TabWidget {
@@ -789,11 +800,11 @@ impl UIWidget for TabWidget {
                             @for (i, (head, id, _)) in self.content.iter().enumerate() {
                                 li class=(if i == self.content.len() { "" } else { "me-2" }) role="presentation" {
                                     button class="inline-block p-4 border-b-2 rounded-t-lg"
-                                    data-tabs-target=(format!("#{id}"))
+                                    data-tabs-target=(format!("#{id}"))x
                                     type="button"
                                     role="tab"
                                     aria-controls=(id)
-                                    aria-selected="false" { (head) };
+                                    aria-selected=(if *id == self.active { "true" } else { "false" }) { (head) };
                                 }
                             };
                         }
diff --git a/src/ui/components/modal.rs b/src/ui/components/modal.rs
index 17f80a8..a248df5 100644
--- a/src/ui/components/modal.rs
+++ b/src/ui/components/modal.rs
@@ -1,7 +1,8 @@
-use maud::{PreEscaped, Render, html};
+use maud::{PreEscaped, html};
 
 use crate::ui::UIWidget;
 
+#[allow(non_snake_case)]
 pub fn ModalCloseButton<T: UIWidget + 'static>(modal: &str, inner: T) -> PreEscaped<String> {
     html! {
         button
@@ -10,6 +11,7 @@ pub fn ModalCloseButton<T: UIWidget + 'static>(modal: &str, inner: T) -> PreEsca
     }
 }
 
+#[allow(non_snake_case)]
 pub fn ModalOpenButton<T: UIWidget + 'static>(modal: &str, inner: T) -> PreEscaped<String> {
     html! {
     button
@@ -19,6 +21,7 @@ pub fn ModalOpenButton<T: UIWidget + 'static>(modal: &str, inner: T) -> PreEscap
     }
 }
 
+#[allow(non_snake_case)]
 pub fn Modal<T: UIWidget + 'static, E: UIWidget + 'static, F: FnOnce(String) -> E>(
     title: &str,
     body: T,
@@ -26,32 +29,29 @@ pub fn Modal<T: UIWidget + 'static, E: UIWidget + 'static, F: FnOnce(String) ->
 ) -> (String, PreEscaped<String>) {
     let id = uuid::Uuid::new_v4().to_string();
 
-    (
-        format!("modal-{id}"),
-        html! {
-            div id=(format!("modal-{id}")) tabindex="-1" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full" {
-                div class="relative p-4 w-full max-w-2xl max-h-full" {
+    (format!("modal-{id}"), html! {
+        div id=(format!("modal-{id}")) tabindex="-1" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full" {
+            div class="relative p-4 w-full max-w-2xl max-h-full" {
 
-            div class="relative bg-white rounded-lg shadow dark:bg-gray-700" {
-                div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600" {
-                    h3 class="text-xl font-semibold text-gray-900 dark:text-white" { (title) }
-                    button type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" data-modal-hide=(format!("modal-{id}")) {
-                        svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14" {
-                            path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" {};
-                        };
-                        span class="sr-only" { "Close modal" };
-                    }
-                };
-
-                div class="p-4 md:p-5 space-y-4" {
-                    (body)
-                };
-
-                div class="flex items-center p-4 md:p-5 border-t border-gray-200 rounded-b dark:border-gray-600" {
-                    (footer(format!("modal-{id}")))
-                };
+        div class="relative bg-white rounded-lg shadow dark:bg-gray-700" {
+            div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600" {
+                h3 class="text-xl font-semibold text-gray-900 dark:text-white" { (title) }
+                button type="button" class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" data-modal-hide=(format!("modal-{id}")) {
+                    svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14" {
+                        path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" {};
+                    };
+                    span class="sr-only" { "Close modal" };
+                }
             };
-                }};
-        },
-    )
+
+            div class="p-4 md:p-5 space-y-4" {
+                (body)
+            };
+
+            div class="flex items-center p-4 md:p-5 border-t border-gray-200 rounded-b dark:border-gray-600" {
+                (footer(format!("modal-{id}")))
+            };
+        };
+            }};
+    })
 }
diff --git a/src/ui/components/shell.rs b/src/ui/components/shell.rs
index 85e3b79..ed5fd23 100644
--- a/src/ui/components/shell.rs
+++ b/src/ui/components/shell.rs
@@ -278,13 +278,10 @@ pub fn BottomNavigationTile<T: UIWidget + 'static>(
 ) -> ClassicWidget<LinkWidget> {
     Classic(
         "inline-flex flex-col items-center justify-center px-5 hover:bg-gray-50 dark:hover:bg-gray-800 group",
-        Link(
-            reference,
-            html! {
-                (icon.map(|x| x.render()).unwrap_or_default());
-                span class="text-sm text-gray-500 dark:text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-500" { (text) };
-            },
-        ),
+        Link(reference, html! {
+            (icon.map(|x| x.render()).unwrap_or_default());
+            span class="text-sm text-gray-500 dark:text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-500" { (text) };
+        }),
     )
 }
 
diff --git a/src/ui/mod.rs b/src/ui/mod.rs
index 34d59cd..a5308dc 100644
--- a/src/ui/mod.rs
+++ b/src/ui/mod.rs
@@ -38,8 +38,8 @@ pub mod prelude {
         MixBlendMode, Opacity, Saturate, Sepia,
     };
     pub use super::primitives::flex::{
-        AlignContent, AlignItems, Direction, DivideStyle, DivideWidth, Flex, FlexBasis, FlexGrow,
-        Justify, JustifyItems, Order, Strategy, Wrap,
+        AlignContent, AlignItems, Column, Direction, DivideStyle, DivideWidth, Flex, FlexBasis,
+        FlexGrow, Justify, JustifyItems, Order, Row, Strategy, Wrap,
     };
     pub use super::primitives::grid::{
         Columns, Grid, GridAmount, GridAutoFlow, GridAutoSize, GridElementColumn, GridElementRow,
@@ -53,7 +53,7 @@ pub mod prelude {
         Range, Select, TextArea, TextInput, TimePicker, Toggle,
     };
     pub use super::primitives::link::Link;
-    pub use super::primitives::list::{OrderedList, UnorderedList};
+    pub use super::primitives::list::{HorizontalList, ListEntry, OrderedList, UnorderedList};
     pub use super::primitives::margin::Margin;
     pub use super::primitives::padding::Padding;
     pub use super::primitives::position::{
@@ -79,7 +79,9 @@ pub mod prelude {
     };
     pub use super::primitives::visibility::Visibility;
     pub use super::primitives::width::{MaxWidth, MinWidth, Width};
-    pub use super::primitives::{Context, NoBrowserAppearance, Nothing, Side, Size, script};
+    pub use super::primitives::{
+        Context, NoBrowserAppearance, Nothing, Optional, Side, Size, script,
+    };
     pub use super::wrapper::{
         _2XLScreen, Hover, LargeScreen, MediumScreen, Screen, SmallScreen, XLScreen,
     };
diff --git a/src/ui/primitives/grid.rs b/src/ui/primitives/grid.rs
index 31d46c1..cd1e345 100644
--- a/src/ui/primitives/grid.rs
+++ b/src/ui/primitives/grid.rs
@@ -274,25 +274,21 @@ impl GridElement {
     }
 
     pub fn span(mut self, value: GridElementValue) -> Self {
-        self.1.push(format!(
-            "{}-span-{}",
-            self.2,
-            match value {
-                GridElementValue::_1 => "1",
-                GridElementValue::_2 => "2",
-                GridElementValue::_3 => "3",
-                GridElementValue::_4 => "4",
-                GridElementValue::_5 => "5",
-                GridElementValue::_6 => "6",
-                GridElementValue::_7 => "7",
-                GridElementValue::_8 => "8",
-                GridElementValue::_9 => "9",
-                GridElementValue::_10 => "10",
-                GridElementValue::_11 => "11",
-                GridElementValue::_12 => "12",
-                GridElementValue::Auto => "full",
-            }
-        ));
+        self.1.push(format!("{}-span-{}", self.2, match value {
+            GridElementValue::_1 => "1",
+            GridElementValue::_2 => "2",
+            GridElementValue::_3 => "3",
+            GridElementValue::_4 => "4",
+            GridElementValue::_5 => "5",
+            GridElementValue::_6 => "6",
+            GridElementValue::_7 => "7",
+            GridElementValue::_8 => "8",
+            GridElementValue::_9 => "9",
+            GridElementValue::_10 => "10",
+            GridElementValue::_11 => "11",
+            GridElementValue::_12 => "12",
+            GridElementValue::Auto => "full",
+        }));
         self
     }
 
diff --git a/src/ui/primitives/input/form.rs b/src/ui/primitives/input/form.rs
index 51d6ffb..b9ba8b3 100644
--- a/src/ui/primitives/input/form.rs
+++ b/src/ui/primitives/input/form.rs
@@ -1,6 +1,4 @@
-use std::{collections::HashMap, fmt::Write};
-
-use maud::{Markup, PreEscaped, Render, html};
+use maud::{Markup, Render, html};
 
 use crate::{
     auth::{User, csrf::CSRF},
diff --git a/src/ui/primitives/input/mod.rs b/src/ui/primitives/input/mod.rs
index 9402a40..5feb21d 100644
--- a/src/ui/primitives/input/mod.rs
+++ b/src/ui/primitives/input/mod.rs
@@ -93,7 +93,7 @@ impl UIWidget for TextInputWidget {
         Vec::new()
     }
 
-    fn render_with_class(&self, class: &str) -> Markup {
+    fn render_with_class(&self, _: &str) -> Markup {
         let mut attrs = self.attrs.clone();
 
         if self.password {
@@ -303,6 +303,7 @@ pub struct NumberInputWidget {
     buttons: bool,
 }
 
+#[allow(non_snake_case)]
 pub fn NumberInput() -> NumberInputWidget {
     NumberInputWidget {
         inner: None,
diff --git a/src/ui/primitives/list.rs b/src/ui/primitives/list.rs
index 447fb4c..160bc86 100644
--- a/src/ui/primitives/list.rs
+++ b/src/ui/primitives/list.rs
@@ -116,6 +116,7 @@ impl UIWidget for ListWidget {
 
 // TODO : List data backed list + reorderable + add + remove + crud
 
+#[allow(non_snake_case)]
 pub fn CheckIconRounded() -> PreEscaped<String> {
     html! {
     svg class="w-3.5 h-3.5 me-2 text-green-500 dark:text-green-400 shrink-0" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20" {
@@ -124,6 +125,7 @@ pub fn CheckIconRounded() -> PreEscaped<String> {
     }
 }
 
+#[allow(non_snake_case)]
 pub fn CheckIconRoundedGray() -> PreEscaped<String> {
     html! {
         svg class="w-3.5 h-3.5 me-2 text-gray-500 dark:text-gray-400 shrink-0" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20" {
@@ -132,6 +134,7 @@ pub fn CheckIconRoundedGray() -> PreEscaped<String> {
     }
 }
 
+#[allow(non_snake_case)]
 pub fn ListEntry<T: UIWidget + 'static, I: UIWidget + 'static>(
     icon: I,
     inner: T,
@@ -144,6 +147,7 @@ pub fn ListEntry<T: UIWidget + 'static, I: UIWidget + 'static>(
     }
 }
 
+#[allow(non_snake_case)]
 pub fn CheckIcon() -> PreEscaped<String> {
     html! {
         svg class="shrink-0 w-3.5 h-3.5 text-green-500 dark:text-green-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 12" {