homepage

Brown Markup Library

Tab Switcher

Change the content presented based on the tab button selected.

Rendered Component

Displaying content for Brown Community

content one

Markup

HTML

<div>
  <div role="tablist" aria-label="file generation tools">
    <button
      aria-controls="tabpanel-1"
      aria-selected="true"
      class="tab-button"
      id="tab-1"
      onclick="onButtonPress(1)"
      role="tab"
      type="button"
    >
      Community
    </button>
    <button
      aria-controls="tabpanel-2"
      aria-selected="false"
      class="tab-button"
      id="tab-2"
      onclick="onButtonPress(2)"
      role="tab"
      type="button"
    >
      Users
    </button>
    <button
      aria-controls="tabpanel-3"
      aria-selected="false"
      class="tab-button"
      id="tab-3"
      onclick="onButtonPress(3)"
      role="tab"
      type="button"
    >
      Groups
    </button>
  </div>
  <p class="screen_reader_text" aria-live="polite" id="content-update">
    Displaying content for Brown Community
  </p>
  <div
    aria-labelledby="tab-1"
    class="content-panel"
    id="tabpanel-1"
    role="tabpanel"
    style=""
    tabindex="0"
  >
    <p>content one</p>
  </div>
  <div
    aria-labelledby="tab-2"
    class="content-panel"
    id="tabpanel-2"
    role="tabpanel"
    style="display:none;"
    tabindex="-1"
  >
    <p>content two</p>
  </div>
  <div
    aria-labelledby="tab-3"
    class="content-panel"
    id="tabpanel-3"
    role="tabpanel"
    style="display:none;"
    tabindex="-1"
  >
    <p>content three</p>
  </div>
  <div></div>
</div>

Styling

CSS

.content-panel {
  padding: 2rem;
  border: 1px solid #b7b09c;
  display: flex;
  flex-direction: column;
  margin-top: 1rem;
}
.screen_reader_text {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}
.tab-button {
  background: transparent;
  border: 0;
  display: inline-block;
  font-size: 0.9375rem;
  font-weight: 700;
  padding: 1.25rem;
  position: relative;
  text-align: center;
  width: auto;
  vertical-align: middle;
}
.tab-button:before {
  border: 6px solid transparent;
  border-top-color: #c00404;
  content: "";
  left: 45%;
  margin-top: 6px;
  opacity: 0;
  position: absolute;
  top: 100%;
  transform: translate(0, -50%);
}
.tab-button:after {
  background: inherit;
  border: 1px solid #b7b09c;
  border-color: #b7b09c;
  bottom: 0;
  content: "";
  display: block;
  height: 6px;
  left: 0;
  position: absolute;
  width: 100%;
}
.tab-button[aria-selected="true"]:before {
  opacity: 1;
}
.tab-button[aria-selected="true"]:after {
  background: #c00404;
  border: 1px solid #c00404;
  border-color: #c00404;
}
@media screen and (prefers-reduced-motion: no-preference) {
  .tab-button:before {
    transition: opacity 0.25s;
  }
}

JS

function onButtonPress(number) {
  const tabButtons = [...document.getElementsByClassName("tab-button")];
  const contentUpdate = document.getElementById("content-update");
  const panels = [...document.getElementsByClassName("content-panel")];
  tabButtons.forEach((button) => {
    if (button.id === `tab-${number}`) {
      button.setAttribute("aria-selected", "true");
      contentUpdate.innerHTML = `displaying content for ${button.innerHTML}`;
    } else {
      button.setAttribute("aria-selected", "false");
    }
  });
  panels.forEach((panel) => {
    if (panel.id === `tabpanel-${number}`) {
      panel.tabIndex = 0;
      panel.setAttribute("style", "");
    } else {
      panel.tabIndex = -1;
      panel.setAttribute("style", "display: none;");
    }
  });
}

Example from the Brown React Component Library

Brown React Component Library Code