Code Block

Collapsed File

A long listing collapsed to its first lines: the tail lives inside details, and the cut is shown by a mask that fades away on expand.

  • code
  • details
  • collapse
  • no-js

Preview

1440pxHost theme

Use it with AI

  1. 1. Copy the link.
  2. 2. Write to your agent in your own words and drop the link into the sentence.
  3. 3. The agent opens the link and installs the component from the registry.

put this in the header: https://vibeui.ru/c/codeblock-006?lang=en

lib/load-user.ts
export async function loadUser(id: string) {
  const response = await fetch(`/api/users/${id}`)

  if (!response.ok) {
Показать ещё 6 строкСвернуть
    throw new Error(`Пользователь ${id} не найден`)
  }

  const user = await response.json()
  return { ...user, loadedAt: Date.now() }
}
Show the full instructions

What the link says, spelled out. Use it when your agent cannot open links — paste this text instead.

# Install and place "codeblock-006" (Collapsed File) from VibeUI

## 1. Install first — do not skip, do not recreate
Run this exact command before writing any code:
npx shadcn@latest add https://vibeui.ru/r/codeblock-006.json

Registry item: https://vibeui.ru/r/codeblock-006.json
Installs to: components/vibeui/codeblock-006.tsx (the exact path follows this project's components.json aliases).
npm dependencies: none.
Registry dependencies: none.

Install it from the registry. Do not recreate it from the description,
do not substitute a similar component from another library, and do not
rewrite it to match the project's existing style.

## 2. What it is
A long listing collapsed to its first lines: the tail lives inside details, and the cut is shown by a mask that fades away on expand.

Long code collapsed to its first lines, expanded by a native details element with a fading cut. Zero dependencies, zero client JS.

## 3. How to use it
import { Codeblock006 } from "@/components/vibeui/codeblock-006"

<Codeblock006
  path="lib/load-user.ts"
  visibleCount={4}
/>

Read the installed file for the full prop list.

## 4. Where to place it
This is a small inline component. Put it exactly where the user asked,
inside the existing markup. Do not create a new page, section or
wrapper for it. If a similar control already sits in that spot,
replace it instead of adding a second one.

Placement: ___
(The user fills this line in. If it is still blank, ask where to put it
instead of guessing.)

## 5. Keep exactly as installed
- the local --vibeui-codeblock-006-* palette — do not swap it for your theme tokens
- the native details: it gives expansion, find-in-page and no-JS behaviour for free
- the visible first lines outside details — otherwise a collapsed block says nothing about itself
- the bottom fade only while collapsed: when open it hides real code
- the changing summary caption: "Show more" and "Collapse" are different promises
- the visible focus ring on summary, or keyboard users cannot tell what expands

## 6. You may change
- the listing rows through the lines array
- the file path through path
- the number of visible rows through visibleCount
- the summary caption and the fade height

## 7. Rules
- The tail inside details is skipped by find-in-page while collapsed: that is the element's own behaviour.
- A visibleCount above the listing length removes the summary entirely — the block becomes plain code.
- A smooth height animation for details is impossible without JS: expansion is instant.
- Do not lift the CSS variables into globals.css: the component has to stay a single file.

## 8. Verify
- it renders with no console errors;
- it looks like the preview on the VibeUI page you copied this from;
- if it does not, you changed something listed in section 5 — put it back.

For developers

npx shadcn@latest add https://vibeui.ru/r/codeblock-006.json
https://vibeui.ru/r/codeblock-006.json

Компонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-codeblock-006-*. Серверный: раскрытие делает нативный details, состояние в JS не хранится. Видимая часть листинга лежит снаружи details, а внутрь уходит только хвост, поэтому первые строки видны всегда. Затухание нижнего края включается селектором :has(details:not([open])) на корне и снимается само при раскрытии. Подпись summary меняется парой span, один из которых прячется по details[open].

Component source

The same file your agent installs. Here in case you would rather copy it by hand.

import type { CSSProperties } from "react"

export type Codeblock006Props = {
  path?: string
  visibleCount?: number
  lines?: string[]
  className?: string
  style?: CSSProperties
}

// Идея компонента: длинный файл, свёрнутый до первых строк. Хвост лежит
// внутри <details>, а «обрыв» показан маской на видимой части — она гаснет,
// как только details открыт, поэтому состояние читается без иконок.
const STYLES = `
:where([data-vibeui-block="codeblock-006"]){
--vibeui-codeblock-006-bg:oklch(0.21 0.024 300);
--vibeui-codeblock-006-head:oklch(0.25 0.028 300);
--vibeui-codeblock-006-fg:oklch(0.93 0.008 300);
--vibeui-codeblock-006-muted:oklch(0.68 0.02 300);
--vibeui-codeblock-006-border:oklch(1 0 0 / 13%);
--vibeui-codeblock-006-accent:oklch(0.8 0.13 310);
--vibeui-codeblock-006-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;
--vibeui-codeblock-006-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
[data-vibeui-block="codeblock-006"]{
display:block;width:100%;max-width:32rem;box-sizing:border-box;margin:0;
overflow:hidden;border:1px solid var(--vibeui-codeblock-006-border);border-radius:0.75rem;
background:var(--vibeui-codeblock-006-bg);color:var(--vibeui-codeblock-006-fg);
font-family:var(--vibeui-codeblock-006-font);
}
[data-vibeui-block="codeblock-006"] [data-part="head"]{
padding:0.5rem 0.875rem;
background:var(--vibeui-codeblock-006-head);
border-bottom:1px solid var(--vibeui-codeblock-006-border);
font-family:var(--vibeui-codeblock-006-mono);font-size:0.75rem;
color:var(--vibeui-codeblock-006-muted);
}
[data-vibeui-block="codeblock-006"] pre{margin:0;padding:0.75rem 0.875rem;overflow-x:auto}
[data-vibeui-block="codeblock-006"] code{
display:block;min-width:max-content;
font-family:var(--vibeui-codeblock-006-mono);
font-size:0.8125rem;line-height:1.65;white-space:pre;
}
[data-vibeui-block="codeblock-006"] [data-part="tail"] pre{padding-top:0}
/* Пока хвост свёрнут, видимая часть гаснет книзу — «здесь ещё есть код». */
[data-vibeui-block="codeblock-006"]:has(details:not([open])) [data-part="peek"]{
mask-image:linear-gradient(to bottom,#000 45%,oklch(0 0 0 / 25%) 100%);
}
[data-vibeui-block="codeblock-006"] summary{
cursor:pointer;list-style:none;
display:flex;align-items:center;justify-content:space-between;gap:0.75rem;
padding:0.5rem 0.875rem;
border-top:1px solid var(--vibeui-codeblock-006-border);
font-size:0.75rem;font-weight:650;color:var(--vibeui-codeblock-006-accent);
transition:background-color .16s ease;
}
[data-vibeui-block="codeblock-006"] summary::-webkit-details-marker{display:none}
[data-vibeui-block="codeblock-006"] summary:hover{background:oklch(1 0 0 / 6%)}
[data-vibeui-block="codeblock-006"] summary:focus-visible{outline:2px solid var(--vibeui-codeblock-006-accent);outline-offset:-2px}
[data-vibeui-block="codeblock-006"] summary::after{content:"▾";transition:transform .18s ease}
[data-vibeui-block="codeblock-006"] details[open] summary::after{transform:rotate(180deg)}
[data-vibeui-block="codeblock-006"] details[open] [data-part="more"]{display:none}
[data-vibeui-block="codeblock-006"] details:not([open]) [data-part="less"]{display:none}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="codeblock-006"] *{animation:none!important;transition:none!important}}
`

const LINES = [
  "export async function loadUser(id: string) {",
  "  const response = await fetch(`/api/users/${id}`)",
  "",
  "  if (!response.ok) {",
  "    throw new Error(`Пользователь ${id} не найден`)",
  "  }",
  "",
  "  const user = await response.json()",
  "  return { ...user, loadedAt: Date.now() }",
  "}",
]

/** Длинный код, свёрнутый до первых строк, с раскрытием через details. */
export function Codeblock006({
  path = "lib/load-user.ts",
  visibleCount = 4,
  lines = LINES,
  className,
  style,
}: Codeblock006Props) {
  const head = lines.slice(0, visibleCount)
  const tail = lines.slice(visibleCount)

  return (
    <>
      <style href="vibeui-codeblock-006" precedence="medium">
        {STYLES}
      </style>
      <figure
        data-vibeui-block="codeblock-006"
        className={className}
        style={style}
      >
        <figcaption data-part="head">{path}</figcaption>
        <pre data-part="peek">
          <code>{head.join("\n")}</code>
        </pre>
        {tail.length > 0 ? (
          <details>
            <summary>
              <span data-part="more">Показать ещё {tail.length} строк</span>
              <span data-part="less">Свернуть</span>
            </summary>
            <div data-part="tail">
              <pre>
                <code>{tail.join("\n")}</code>
              </pre>
            </div>
          </details>
        ) : null}
      </figure>
    </>
  )
}