Code Block

code-block.svelte

Code blocks are used to display code snippets in a formatted manner.

Demo

001 package main
002
003 import "fmt"
004
005 func main() {
006 fmt.Println("Hello, World!")
007 }
Usage
001 <script lang="ts">
002 import CodeBlock from '$lib/components/code-block.svelte';
003
004 const code: string = `package main
005
006 import "fmt"
007
008 func main() {
009 fmt.Println("Hello, World!")
010 }`;
011 </script>
012
013 <CodeBlock {code} />
014
code-block.svelte
001 <script lang="ts" module>
002 import type { HTMLAttributes } from 'svelte/elements';
003
004 export type CodeBlockProps = HTMLAttributes<HTMLDivElement> & {
005 ref?: HTMLDivElement | null;
006 code?: string;
007 };
008 </script>
009
010 <script lang="ts">
011 let { class: className, ref = $bindable(null), code, ...restProps }: CodeBlockProps = $props();
012 </script>
013
014 <div class={`code-block ${className ?? ''}`} bind:this={ref} {...restProps}>
015 {#if code}
016 <div class="lines">
017 {#each code.split('\n') as line, index (index)}
018 <div class="code-line">
019 <span class="line-number">{String(index + 1).padStart(3, '0')}</span>
020 <span class="line-content">{line}</span>
021 </div>
022 {/each}
023 </div>
024 {/if}
025 </div>
026
027 <style>
028 .code-block {
029 font-family: inherit;
030 display: block;
031 overflow-x: auto;
032 background-color: var(--border-muted);
033 font-weight: 400;
034 }
035
036 /*
037 Wrap every row in one inline-block so all rows stretch to the width of
038 the longest line — their block-width fills the inner's content box, which
039 is max-content (the widest row). Without this, scrollable blocks show the
040 per-line background ending early on lines shorter than the widest one.
041 */
042 .lines {
043 display: inline-block;
044 min-width: 100%;
045 }
046
047 .code-line {
048 display: flex;
049 align-items: flex-start;
050 justify-content: space-between;
051 }
052
053 .line-number {
054 display: inline-flex;
055 width: 3ch;
056 flex-shrink: 0;
057 background-color: var(--surface-base);
058 padding-right: 1ch;
059 text-align: right;
060 opacity: 0.5;
061 user-select: none;
062 }
063
064 .line-content {
065 flex: 1;
066 min-width: 0;
067 background-color: var(--border-muted);
068 padding-left: 2ch;
069 white-space: pre;
070 }
071 </style>
072