Marca: ·

App shell

Escritorio

Armazón de la aplicación: cabecera (banner), navegación lateral (navigation con nombre), contenido (main) y pie (contentinfo), con un enlace para saltar al contenido. La navegación son datos: el consumidor marca la página actual (current, que se pinta como aria-current="page") y responde a navigate con el evento nativo, para usar su router sin que FLT dependa de ninguno. Los grupos son botones de divulgación (aria-expanded), no menús, y se abren solos si contienen la página actual. Aquí el marco mide 64rem, el ancho a partir del cual la navegación va en línea; desplázalo en horizontal si no cabe. Por ser una demo, su main queda dentro del main del escaparate.

Saltar al contenido
FLT Banca

Cuenta corriente

Saldo disponible: 2.430,18 €

<flt-app-shell>
  <flt-app-header>
    <span fltAppHeaderBrand>FLT Banca</span>
    <flt-button fltAppHeaderActions variant="ghost" size="sm">Salir</flt-button>
  </flt-app-header>
  <flt-side-nav [items]="items()" (navigate)="onNavigate($event)" />
  <h1>{{ title() }}</h1>
  <flt-app-footer>© 2026 FLT Banca · <a href="/aviso-legal">Aviso legal</a></flt-app-footer>
</flt-app-shell>

// items: [{ id, label, href, current? }, { id, label, children: [{ id, label, href, current? }] }]
onNavigate({ item, event }: FltNavigateEvent) {
  event.preventDefault();
  this.router.navigateByUrl(item.href);
}
<FltAppShell>
  <template #header>
    <FltAppHeader>
      <template #brand>FLT Banca</template>
      <template #actions><FltButton variant="ghost" size="sm">Salir</FltButton></template>
    </FltAppHeader>
  </template>
  <template #nav><FltSideNav :items="items" @navigate="onNavigate" /></template>
  <h1>{{ title }}</h1>
  <template #footer>
    <FltAppFooter>© 2026 FLT Banca · <a href="/aviso-legal">Aviso legal</a></FltAppFooter>
  </template>
</FltAppShell>

function onNavigate({ item, event }: FltNavigateEvent) {
  event.preventDefault();
  router.push(item.href);
}

Móvil

Por debajo de 64rem de su propio ancho (container query) la navegación sale de la página y aparece el botón Menú en la cabecera: abre la navegación como un drawer modal desde el inicio, con el foco dentro, Escape para cerrar y vuelta del foco al botón. Al elegir una página el drawer se cierra; si el armazón se ensancha con el drawer abierto, también.

Saltar al contenido
FLT Banca

Cuenta corriente

Saldo disponible: 2.430,18 €

<flt-app-shell>
  <flt-app-header>
    <span fltAppHeaderBrand>FLT Banca</span>
    <flt-button fltAppHeaderActions variant="ghost" size="sm">Salir</flt-button>
  </flt-app-header>
  <flt-side-nav [items]="items()" (navigate)="onNavigate($event)" />
  <h1>{{ title() }}</h1>
  <flt-app-footer>© 2026 FLT Banca · <a href="/aviso-legal">Aviso legal</a></flt-app-footer>
</flt-app-shell>

// items: [{ id, label, href, current? }, { id, label, children: [{ id, label, href, current? }] }]
onNavigate({ item, event }: FltNavigateEvent) {
  event.preventDefault();
  this.router.navigateByUrl(item.href);
}
<FltAppShell>
  <template #header>
    <FltAppHeader>
      <template #brand>FLT Banca</template>
      <template #actions><FltButton variant="ghost" size="sm">Salir</FltButton></template>
    </FltAppHeader>
  </template>
  <template #nav><FltSideNav :items="items" @navigate="onNavigate" /></template>
  <h1>{{ title }}</h1>
  <template #footer>
    <FltAppFooter>© 2026 FLT Banca · <a href="/aviso-legal">Aviso legal</a></FltAppFooter>
  </template>
</FltAppShell>

function onNavigate({ item, event }: FltNavigateEvent) {
  event.preventDefault();
  router.push(item.href);
}