diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md
index 716f0ee..8044e26 100644
--- a/REQUIREMENTS.md
+++ b/REQUIREMENTS.md
@@ -121,7 +121,7 @@ slhx competes with React by making frontend frameworks unnecessary for most apps
## page_swap
### req: page_swap/001
-001 Minimal page swapping is a first-class slhx-axum happy path. Authors mark real anchors with `data-slhx-nav`; links keep valid `href` and work without JS. Missing `href` on a static `data-slhx-nav` anchor is a build error.
+001 Minimal page swapping is a first-class slhx-axum happy path. Authors mark real anchors with `data-slhx-nav`; links keep valid `href` and work without JS. Missing or empty static `href` on a `data-slhx-nav` anchor is a build error.
### req: page_swap/002
002 A `data-slhx-nav` click fetches the target URL as a slhx partial request. The response updates the canonical content slot, optionally navigation and title, then applies a `Navigate` effect.
diff --git a/slhx-build/src/lib.rs b/slhx-build/src/lib.rs
index f1200d6..3c27714 100644
--- a/slhx-build/src/lib.rs
+++ b/slhx-build/src/lib.rs
@@ -1067,7 +1067,9 @@ fn reject_invalid_slhx_attr_values(path: &Path, attrs: &[SurfaceAttribute]) -> i
}
fn reject_invalid_slhx_attr_placement(path: &Path, tag: &str, attrs: &[SurfaceAttribute]) -> io::Result<()> {
- if has_attr(attrs, "data-slhx-nav") && (tag != "a" || !has_attr(attrs, "href")) {
+ if has_attr(attrs, "data-slhx-nav")
+ && (tag != "a" || !has_attr(attrs, "href") || static_attr(attrs, "href").is_some_and(|href| href.trim().is_empty()))
+ {
return Err(invalid_slhx_placement(
path,
"data-slhx-nav",
@@ -1665,6 +1667,12 @@ fn main() {{
"data-slhx-nav",
"",
),
+ (
+ "nav-empty-href",
+ r#"Docs"#,
+ "data-slhx-nav",
+ "",
+ ),
(
"boost-anchor",
r#"Docs"#,