Access Control

System for controlling access.

Invoice #4471 viewer

Buttons a viewer cannot use are hidden entirely, not just disabled.

html

<div class="acc acc--viewer">
  <div class="acc__header">Invoice #4471 <span class="acc__role">viewer</span></div>
  <div class="acc__actions">
    <button type="button" class="acc__btn acc__btn--view" style="background:#BFD9F2;">View</button>
    <button type="button" class="acc__btn acc__btn--edit">Edit</button>
    <button type="button" class="acc__btn acc__btn--delete">Delete</button>
  </div>
  <p class="acc__note">Buttons a viewer cannot use are hidden entirely, not just disabled.</p>
</div>
<style>
.acc { font: 13px/1.5 system-ui, sans-serif; color: #241430; background: #FAF7F2; padding: 18px; border-radius: 12px; width: 300px; box-sizing: border-box; }
.acc__header { font-weight: 700; margin-bottom: 12px; display: flex; align-items: center; justify-content: space-between; }
.acc__role { font-size: 10px; font-weight: 600; text-transform: uppercase; background: #24143014; padding: 3px 8px; border-radius: 999px; }
.acc__actions { display: flex; gap: 8px; }
.acc__btn { border: none; padding: 9px 14px; border-radius: 8px; font: 600 12px system-ui, sans-serif; cursor: pointer; }
.acc__btn--view { color: #241430; }
.acc__btn--edit { display: none; background: #24143014; color: #241430; }
.acc__btn--delete { display: none; background: #241430; color: #FAF7F2; }
.acc--editor .acc__btn--edit, .acc--admin .acc__btn--edit { display: inline-block; }
.acc--admin .acc__btn--delete { display: inline-block; }
.acc__note { margin: 10px 0 0; font-size: 10px; color: #24143099; }
</style>

tailwind

<div class="acctw acctw--viewer font-sans text-[#241430] bg-[#FAF7F2] p-4.5 rounded-xl w-[300px] box-border">
  <div class="font-bold mb-3 flex items-center justify-between">Invoice #4471 <span class="text-[10px] font-semibold uppercase bg-[#24143014] py-0.5 px-2 rounded-full">viewer</span></div>
  <div class="flex gap-2">
    <button type="button" class="border-none py-2 px-3.5 rounded-lg font-semibold text-xs cursor-pointer" style="background:#BFD9F2;">View</button>
    <button type="button" class="acctw__edit hidden border-none py-2 px-3.5 rounded-lg font-semibold text-xs cursor-pointer bg-[#24143014] text-[#241430]">Edit</button>
    <button type="button" class="acctw__delete hidden border-none py-2 px-3.5 rounded-lg font-semibold text-xs cursor-pointer bg-[#241430] text-[#FAF7F2]">Delete</button>
  </div>
  <p class="mt-2.5 text-[10px] text-[#24143099]">Buttons a viewer cannot use are hidden entirely, not just disabled.</p>
</div>
<style>
.acctw--editor .acctw__edit, .acctw--admin .acctw__edit { display: inline-block; }
.acctw--admin .acctw__delete { display: inline-block; }
</style>

react

export function AccessControl({
  panelTitle = "Invoice #4471",
  role = "viewer",
  accent = "#BFD9F2",
  showDeniedNote = true,
}) {
  const canEdit = role === "editor" || role === "admin";
  const canDelete = role === "admin";
  return (
    <div style={{ font: "13px/1.5 system-ui, sans-serif", color: "#241430", background: "#FAF7F2", padding: 18, borderRadius: 12, width: 300, boxSizing: "border-box" }}>
      <div style={{ fontWeight: 700, marginBottom: 12, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
        {panelTitle} <span style={{ fontSize: 10, fontWeight: 600, textTransform: "uppercase", background: "#24143014", padding: "3px 8px", borderRadius: 999 }}>{role}</span>
      </div>
      <div style={{ display: "flex", gap: 8 }}>
        <button type="button" style={{ border: "none", padding: "9px 14px", borderRadius: 8, fontWeight: 600, fontSize: 12, cursor: "pointer", background: accent }}>View</button>
        {canEdit && <button type="button" style={{ border: "none", padding: "9px 14px", borderRadius: 8, fontWeight: 600, fontSize: 12, cursor: "pointer", background: "#24143014", color: "#241430" }}>Edit</button>}
        {canDelete && <button type="button" style={{ border: "none", padding: "9px 14px", borderRadius: 8, fontWeight: 600, fontSize: 12, cursor: "pointer", background: "#241430", color: "#FAF7F2" }}>Delete</button>}
      </div>
      {showDeniedNote && <p style={{ margin: "10px 0 0", fontSize: 10, color: "#24143099" }}>Buttons a {role} cannot use are hidden entirely, not just disabled.</p>}
    </div>
  );
}