🔥 Oxide UI v0.1.0 — Dark mode only, copy-paste ready. Get started →
Skip to content

Code Block

<pre><code> + copy button

Styled code display with language badge and one-click copy. Supports tabbed multi-language blocks. VitePress handles syntax highlighting automatically via Shiki — these patterns are for rendering code in your Nuxt app.

Overview

Preview
bash
npm install @headlessui/vue
npm install @nuxtjs/tailwindcss
npm install @headlessui/vue
npm install @nuxtjs/tailwindcss

Single language block

html
<div class="overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900">
  <!-- Header bar -->
  <div class="flex items-center justify-between border-b border-zinc-800 px-4 py-2.5">
    <span class="text-[10px] font-semibold uppercase tracking-widest text-zinc-500">bash</span>

    <button @click="copy"
      class="flex items-center gap-1.5 rounded-md px-2 py-1 text-[10px] font-medium transition-all"
      :class="copied ? 'text-emerald-400' : 'text-zinc-600 hover:bg-zinc-800 hover:text-zinc-300'"
    >
      <!-- copy / check icon -->
      {{ copied ? 'Copied!' : 'Copy' }}
    </button>
  </div>

  <!-- Code -->
  <pre class="overflow-x-auto px-4 py-4 text-[13px] leading-relaxed font-mono text-zinc-300"><code>{{ code }}</code></pre>
</div>

Copy to clipboard (Vue)

vue
<script setup>
import { ref } from 'vue'

const props = defineProps({ code: String })
const copied = ref(false)

async function copy() {
  try {
    await navigator.clipboard.writeText(props.code)
  } catch {
    // fallback for older browsers
    const el = document.createElement('textarea')
    el.value = props.code
    document.body.appendChild(el)
    el.select()
    document.execCommand('copy')
    document.body.removeChild(el)
  }
  copied.value = true
  setTimeout(() => { copied.value = false }, 2000)
}
</script>

Tabbed multi-language block

vue
<script setup>
import { ref } from 'vue'

const activeTab = ref(0)
const tabs = [
  { lang: 'npm',  code: 'npm install @headlessui/vue' },
  { lang: 'pnpm', code: 'pnpm add @headlessui/vue' },
  { lang: 'yarn', code: 'yarn add @headlessui/vue' },
]
</script>

<template>
  <div class="overflow-hidden rounded-xl border border-zinc-800 bg-zinc-900">
    <div class="flex items-center justify-between border-b border-zinc-800 pr-3">
      <!-- Tab headers -->
      <div class="flex">
        <button
          v-for="(tab, i) in tabs"
          :key="tab.lang"
          @click="activeTab = i"
          class="px-4 py-2.5 text-[11px] font-semibold uppercase tracking-widest transition-colors"
          :class="activeTab === i
            ? 'border-b-2 border-[#D40C37] text-zinc-200'
            : 'text-zinc-600 hover:text-zinc-400'"
        >{{ tab.lang }}</button>
      </div>
      <!-- Copy button -->
      <button @click="copy(tabs[activeTab].code)" ...>Copy</button>
    </div>
    <pre class="overflow-x-auto px-4 py-4 text-[13px] leading-relaxed font-mono text-zinc-300"><code>{{ tabs[activeTab].code }}</code></pre>
  </div>
</template>

For production, use Shiki for proper tokenised syntax highlighting:

bash
npm install shiki
vue
<!-- server component or composable -->
<script setup>
import { createHighlighter } from 'shiki'

const highlighter = await createHighlighter({
  themes: ['vesper'],    // dark theme
  langs: ['vue', 'ts', 'bash', 'html', 'css'],
})

const html = highlighter.codeToHtml(code, {
  lang: 'vue',
  theme: 'vesper',
})
</script>

<template>
  <div class="rounded-xl border border-zinc-800 bg-zinc-900 overflow-hidden">
    <!-- Shiki outputs its own <pre><code> with inline colour tokens -->
    <div v-html="html" class="[&_pre]:overflow-x-auto [&_pre]:p-4 [&_pre]:text-[13px]"></div>
  </div>
</template>

Accessibility notes

  • <pre><code> is the semantic element for preformatted code — don't replace it with <div>
  • Add aria-label="Copy code" on the copy button since it may contain only an icon
  • After a successful copy, announce with role="status" or by changing the button text (which is already done via copied state)
  • Long lines should scroll horizontally — set overflow-x: auto and never break line wrapping on code blocks

Released under the MIT License.