Route Guard

Logic controlling access to a route.

Billing settings Allowed

html

<div class="guard" style="--accent:#241430;">
  <a class="guard__link" href="#" >
    <span class="guard__lock" aria-hidden="true"></span>Billing settings
  </a>
  
  <span class="guard__badge guard__badge--allowed">Allowed</span>
</div>
<style>
.guard { display: flex; align-items: center; gap: 10px; font: 14px system-ui, sans-serif; color: #241430; }
.guard__link { display: inline-flex; align-items: center; gap: 6px; text-decoration: none; color: #241430; padding: 8px 10px; border-radius: 8px; }
.guard__link:hover { background: #FAF7F2; }
.guard__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.guard__link[aria-disabled="true"] { opacity: .45; pointer-events: none; }
.guard__lock { width: 10px; height: 8px; border: 2px solid currentColor; border-radius: 2px; position: relative; }
.guard__lock::before { content: ""; position: absolute; left: 1px; top: -6px; width: 6px; height: 6px; border: 2px solid currentColor; border-bottom: none; border-radius: 6px 6px 0 0; }
.guard__badge { font-size: 12px; padding: 3px 9px; border-radius: 999px; }
.guard__badge--allowed { background: rgba(168,230,193,.5); color: #1c6b3c; }
.guard__badge--blocked { background: rgba(36,20,48,.08); color: #241430; }
</style>

tailwind

<div class="flex items-center gap-2.5 font-sans text-sm text-[#241430]" style="--accent:#241430;">
  <a class="route-guard-tw__link inline-flex items-center gap-1.5 no-underline text-[#241430] px-2.5 py-2 rounded-lg hover:bg-[#FAF7F2]" href="#" >
    <span class="route-guard-tw__lock w-2.5 h-2 border-2 border-current rounded-sm relative" aria-hidden="true"></span>Billing settings
  </a>
  
  <span class="text-xs px-2.5 py-1 rounded-full bg-[#A8E6C1]/50 text-[#1c6b3c]">Allowed</span>
</div>
<style>
.route-guard-tw__link[aria-disabled="true"] { opacity: .45; pointer-events: none; }
.route-guard-tw__link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.route-guard-tw__lock::before { content: ""; position: absolute; left: 1px; top: -6px; width: 6px; height: 6px; border: 2px solid currentColor; border-bottom: none; border-radius: 6px 6px 0 0; }
</style>

react

export function RouteGuard({
  label = "Billing settings",
  requirement = "Admin role",
  blocked = false,
  accent = "#241430",
}) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10, fontFamily: "system-ui, sans-serif", fontSize: 14, color: "#241430" }}>
      <a
        href="#"
        aria-disabled={blocked ? "true" : undefined}
        tabIndex={blocked ? -1 : undefined}
        style={{ display: "inline-flex", alignItems: "center", gap: 6, textDecoration: "none", color: "#241430", padding: "8px 10px", borderRadius: 8, opacity: blocked ? .45 : 1, pointerEvents: blocked ? "none" : "auto" }}
      >
        <span aria-hidden="true" style={{ width: 10, height: 8, border: "2px solid currentColor", borderRadius: 2 }} />
        {label}
      </a>
      {blocked ? (
        <span style={{ fontSize: 12, padding: "3px 9px", borderRadius: 999, background: "rgba(36,20,48,.08)", color: "#241430" }}>Blocked &middot; requires {requirement}</span>
      ) : (
        <span style={{ fontSize: 12, padding: "3px 9px", borderRadius: 999, background: "rgba(168,230,193,.5)", color: "#1c6b3c" }}>Allowed</span>
      )}
    </div>
  );
}