diff --git a/leptos/tests/ssr.rs b/leptos/tests/ssr.rs index 999989937..2b8e62108 100644 --- a/leptos/tests/ssr.rs +++ b/leptos/tests/ssr.rs @@ -103,6 +103,76 @@ fn test_classes() { assert_eq!(rendered.to_html(), "
"); } +#[cfg(feature = "ssr")] +#[test] +fn test_class_with_class_directive_merge() { + use leptos::prelude::*; + + // class= followed by class: should merge + let rendered: View> = view! { +
+ }; + + assert_eq!(rendered.to_html(), "
"); +} + +#[cfg(feature = "ssr")] +#[test] +fn test_solo_class_directive() { + use leptos::prelude::*; + + // Solo class: directive should work without class attribute + let rendered: View> = view! { +
+ }; + + assert_eq!(rendered.to_html(), "
"); +} + +#[cfg(feature = "ssr")] +#[test] +fn test_class_directive_with_static_class() { + use leptos::prelude::*; + + // class:foo comes after class= due to macro sorting + // The class= clears buffer, then class:foo appends + let rendered: View> = view! { +
+ }; + + // After macro sorting: class="bar" class:foo=true + // Expected: "bar foo" + assert_eq!(rendered.to_html(), "
"); +} + +#[cfg(feature = "ssr")] +#[test] +fn test_global_class_applied() { + use leptos::prelude::*; + + // Test that a global class is properly applied + let rendered: View> = view! { class="global", +
+ }; + + assert_eq!(rendered.to_html(), "
"); +} + +#[cfg(feature = "ssr")] +#[test] +fn test_multiple_class_attributes_overwrite() { + use leptos::prelude::*; + + // When multiple class attributes are applied, the last one should win (browser behavior) + // This simulates what happens when attributes are combined programmatically + let el = leptos::html::div().class("first").class("second"); + + let html = el.to_html(); + + // The second class attribute should overwrite the first + assert_eq!(html, "
"); +} + #[cfg(feature = "ssr")] #[test] fn ssr_with_styles() { diff --git a/tachys/src/html/class.rs b/tachys/src/html/class.rs index ce3bf70c9..3fcad1167 100644 --- a/tachys/src/html/class.rs +++ b/tachys/src/html/class.rs @@ -57,6 +57,10 @@ where _style: &mut String, _inner_html: &mut String, ) { + // If this is a class="..." attribute (not class:name=value), clear previous value + if self.class.should_overwrite() { + class.clear(); + } class.push(' '); self.class.to_html(class); } @@ -156,6 +160,12 @@ pub trait IntoClass: Send { /// Renders the class to HTML. fn to_html(self, class: &mut String); + /// Whether this class attribute should overwrite previous class values. + /// Returns `true` for `class="..."` attributes, `false` for `class:name=value` directives. + fn should_overwrite(&self) -> bool { + false + } + /// Renders the class to HTML for a `