Navigation

navigation.svelte

A top nav bar with logo and left, center, right slots.

Demo

Usage
001 <script lang="ts">
002 import Navigation from '$lib/components/navigation.svelte';
003 import ActionButton from '$lib/components/action-button.svelte';
004 </script>
005
006 <Navigation logoHref="#">
007 {#snippet logo()}svtui{/snippet}
008 {#snippet left()}
009 <ActionButton>files</ActionButton>
010 {/snippet}
011 {#snippet right()}
012 <ActionButton>settings</ActionButton>
013 {/snippet}
014 </Navigation>
015
navigation.svelte
001 <script lang="ts" module>
002 import type { HTMLAttributes } from 'svelte/elements';
003 import type { Snippet } from 'svelte';
004
005 /** A top nav bar with a logo slot and left/center/right sections. */
006 export type NavigationProps = HTMLAttributes<HTMLElement> & {
007 ref?: HTMLElement | null;
008 logoHref?: string;
009 logoTarget?: string;
010 onclicklogo?: (e: MouseEvent) => void;
011 logo?: Snippet;
012 left?: Snippet;
013 right?: Snippet;
014 };
015 </script>
016
017 <script lang="ts">
018 let {
019 class: className,
020 ref = $bindable(null),
021 logoHref,
022 logoTarget,
023 onclicklogo,
024 logo,
025 left,
026 right,
027 children,
028 ...restProps
029 }: NavigationProps = $props();
030 </script>
031
032 <nav class={`nav ${className ?? ''}`} bind:this={ref} {...restProps}>
033 {#if logoHref}
034 <a class="logo" href={logoHref} target={logoTarget}>
035 {@render logo?.()}
036 </a>
037 {:else}
038 <button class="logo" type="button" onclick={onclicklogo}>
039 {@render logo?.()}
040 </button>
041 {/if}
042 <section class="left">
043 {@render left?.()}
044 </section>
045 <section class="children">
046 {@render children?.()}
047 </section>
048 <section class="right">
049 {@render right?.()}
050 </section>
051 </nav>
052
053 <style>
054 .nav {
055 display: flex;
056 align-items: center;
057 justify-content: space-between;
058 background: var(--border-default);
059 }
060
061 .logo {
062 flex-shrink: 0;
063 padding: 0 1ch;
064 display: inline-flex;
065 color: var(--text-primary);
066 background: var(--border-default);
067 text-decoration: none;
068 border: 0;
069 outline: 0;
070 border-radius: 0;
071 margin: 0;
072 font-size: var(--font-size);
073 cursor: pointer;
074 }
075
076 .logo:hover,
077 .logo:focus-visible {
078 background: var(--focus-ring);
079 }
080
081 .logo:focus-visible {
082 outline: none;
083 }
084
085 .left {
086 flex-shrink: 0;
087 }
088
089 .children {
090 min-width: 10%;
091 width: 100%;
092 }
093
094 .right {
095 flex-shrink: 0;
096 }
097 </style>
098