CodeBlock

A block of code with syntax highlighting, a language badge and copying.

import { createApp } from 'vue'
import App from './App.vue'
import '@hina-ui/vue/styles/tokens.css'

createApp(App).mount('#app')
ts
<script setup lang="ts">
  import { CodeBlock } from '@hina-ui/vue'

  const source = `import { createApp } from 'vue'
import App from './App.vue'
import '@hina-ui/vue/styles/tokens.css'

createApp(App).mount('#app')`
</script>

<template>
  <CodeBlock :code="source" lang="ts" class="w-full max-w-xl" />
</template>
vue

Usage

import { CodeBlock } from '@hina-ui/vue'
ts

code is required and is rendered verbatim. lang names the language, which drives highlighting and the badge in the top corner.

pnpm add @hina-ui/vue
bash
<script setup lang="ts">
  import { CodeBlock } from '@hina-ui/vue'
</script>

<template>
  <CodeBlock code="pnpm add @hina-ui/vue" lang="bash" class="w-full max-w-xl" />
</template>
vue

Examples

Badge text

The badge shows lang by default. Set label to show a file name or another note instead; highlighting still follows lang.

export default defineNuxtConfig({
  css: ['@hina-ui/vue/styles/tokens.css'],
})
nuxt.config.ts
<script setup lang="ts">
  import { CodeBlock } from '@hina-ui/vue'

  const source = `export default defineNuxtConfig({
  css: ['@hina-ui/vue/styles/tokens.css'],
})`
</script>

<template>
  <CodeBlock :code="source" lang="ts" label="nuxt.config.ts" class="w-full max-w-xl" />
</template>
vue

Without highlighting

With no lang, nothing is highlighted and no badge is shown; the code appears as written. Command output and plain text suit this.

✔ dependencies installed
✔ style entry ready
  run pnpm dev to start the dev server
<script setup lang="ts">
  import { CodeBlock } from '@hina-ui/vue'

  const output = `✔ dependencies installed
✔ style entry ready
  run pnpm dev to start the dev server`
</script>

<template>
  <CodeBlock :code="output" class="w-full max-w-xl" />
</template>
vue

Copy button

A copy button sits in the top corner by default. Set copyable to false to remove it.

git switch -c feature/hina-ui
bash
<script setup lang="ts">
  import { CodeBlock } from '@hina-ui/vue'
</script>

<template>
  <CodeBlock
    code="git switch -c feature/hina-ui"
    lang="bash"
    :copyable="false"
    class="w-full max-w-xl"
  />
</template>
vue

Long lines

Code does not wrap. Anything wider than the block scrolls horizontally inside it, so the page itself is never stretched. The scrolling area can take focus, after which arrow keys scroll it.

const theme = { accent: 'var(--hn-accent)', radius: 'var(--hn-radius-lg)', shadow: 'var(--hn-shadow-sm)', font: 'var(--hn-font-sans)' }
ts
<script setup lang="ts">
  import { CodeBlock } from '@hina-ui/vue'

  const source = `const theme = { accent: 'var(--hn-accent)', radius: 'var(--hn-radius-lg)', shadow: 'var(--hn-shadow-sm)', font: 'var(--hn-font-sans)' }`
</script>

<template>
  <CodeBlock :code="source" lang="ts" class="w-full max-w-md" />
</template>
vue

Height

Set height through class or style to scroll overflowing code vertically. Long lines still scroll horizontally, while the badge and copy button stay in the top corner.

const value1 = { name: 'Hina UI', enabled: true }
const value2 = { name: 'Hina UI', enabled: true }
const value3 = { name: 'Hina UI', enabled: true }
const value4 = { name: 'Hina UI', enabled: true }
const value5 = { name: 'Hina UI', enabled: true }
const value6 = { name: 'Hina UI', enabled: true }
const value7 = { name: 'Hina UI', enabled: true }
const value8 = { name: 'Hina UI', enabled: true }
const value9 = { name: 'Hina UI', enabled: true }
const value10 = { name: 'Hina UI', enabled: true }
const value11 = { name: 'Hina UI', enabled: true }
const value12 = { name: 'Hina UI', enabled: true }
const value13 = { name: 'Hina UI', enabled: true }
const value14 = { name: 'Hina UI', enabled: true }
const value15 = { name: 'Hina UI', enabled: true }
const value16 = { name: 'Hina UI', enabled: true }
ts
<script setup lang="ts">
  import { CodeBlock } from '@hina-ui/vue'

  const source = Array.from(
    { length: 16 },
    (_, index) => 'const value' + (index + 1) + " = { name: 'Hina UI', enabled: true }",
  ).join('\n')
</script>

<template>
  <CodeBlock :code="source" lang="ts" class="h-48 w-full max-w-lg" />
</template>
vue

Set max-height to limit the height. Short content keeps its natural height; vertical scrolling starts when the content exceeds the limit.

const value1 = { name: 'Hina UI', enabled: true }
const value2 = { name: 'Hina UI', enabled: true }
const value3 = { name: 'Hina UI', enabled: true }
const value4 = { name: 'Hina UI', enabled: true }
const value5 = { name: 'Hina UI', enabled: true }
const value6 = { name: 'Hina UI', enabled: true }
const value7 = { name: 'Hina UI', enabled: true }
const value8 = { name: 'Hina UI', enabled: true }
const value9 = { name: 'Hina UI', enabled: true }
const value10 = { name: 'Hina UI', enabled: true }
const value11 = { name: 'Hina UI', enabled: true }
const value12 = { name: 'Hina UI', enabled: true }
const value13 = { name: 'Hina UI', enabled: true }
const value14 = { name: 'Hina UI', enabled: true }
const value15 = { name: 'Hina UI', enabled: true }
const value16 = { name: 'Hina UI', enabled: true }
ts
<script setup lang="ts">
  import { CodeBlock } from '@hina-ui/vue'

  const source = Array.from(
    { length: 16 },
    (_, index) => 'const value' + (index + 1) + " = { name: 'Hina UI', enabled: true }",
  ).join('\n')
</script>

<template>
  <CodeBlock :code="source" lang="ts" class="max-h-48 w-full max-w-lg" />
</template>
vue

Pre-highlighted code

The html property accepts markup that has already been highlighted. Once given, the component skips highlighting and renders that markup directly, while code is still used for copying.

Highlighting on the server or at build time keeps the browser from downloading a highlighter. Every code block on this site works that way.

const accent = '#39c5bb'
ts
<script setup lang="ts">
  import { CodeBlock } from '@hina-ui/vue'

  const code = `const accent = '#39c5bb'`
  const html = `<span style="color:#8250df">const</span><span> accent = </span><span style="color:#0a3069">'#39c5bb'</span>`
</script>

<template>
  <CodeBlock :code="code" :html="html" lang="ts" class="w-full max-w-xl" />
</template>
vue

Accessibility

  • The scrolling area can take focus and is then scrolled with arrow keys; the focus ring appears around the block.
  • The accessible name of that area comes from the badge, falling back to a generic name when no badge is set.
  • The copy button is named “Copy code” and becomes “Copied” on success.

API

Props

Prop
Type
Default
Description
code
string
—
Required. The code text, also used for copying
lang
string
—
Language, driving highlighting and the badge
label
string
—
Badge text, overriding lang
html
string
—
Pre-highlighted markup; skips highlighting
copyable
boolean
true
Whether to show the copy button
class
string
—
Classes appended to the root