SDK & Integration

Rendering content and styling code blocks

Updated 84 views

Kookee returns entry bodies as ready-to-render HTML in the contentHtml field. You do not need a Markdown parser — the conversion happens server-side.

Render the HTML

React: render it with EntryContent from @kookee/react:

tsx
import { EntryContent } from '@kookee/react/entry';

const post = await kookee.blog.getBySlug(slug);

<EntryContent entry={post} className="prose" />

It adds the kookee-entry-content class the stylesheets below are scoped to, works in React Server Components, and keeps the body's DOM when the parent re-renders. An inline dangerouslySetInnerHTML={{ __html }} does not: in React 19 it replaces the whole body on every render of the parent. Without the package, add the class yourself, and in a client component memoise the { __html } object:

tsx
const html = useMemo(() => ({ __html: post.contentHtml }), [post.contentHtml]);

<div className="kookee-entry-content" dangerouslySetInnerHTML={html} />

Vue:

vue
<div class="kookee-entry-content" v-html="post.contentHtml" />

Both of these inject raw HTML, which is safe here because the content comes from your own dashboard and your own authors — the same trust level as your application code. Do not pipe user-submitted content through the same path without sanitizing it first.

Remember that contentHtml is only present on single-entry fetches. List items do not include it.

Import the code block stylesheet

The SDK ships CSS for code blocks:

TypeScript
// In your entry file — main.ts, App.tsx, or layout.tsx
import '@kookee/sdk/styles/content.css';

Or over a CDN:

HTML
<link rel="stylesheet" href="https://unpkg.com/@kookee/sdk/styles/content.css">

Without it, code blocks render as unstyled preformatted text.

Every rule in it is scoped to the kookee-entry-content class, so the element that holds the HTML needs that class. EntryContent adds it.

What the stylesheet provides

A theme inspired by VS Code Dark+, applied to these classes:

  • .kookee-code-block — the wrapper, with a dark background

  • .kookee-code-block__header — language label and copy button row

  • .kookee-code-block__language — the language label

  • .kookee-code-block__copy — the copy button

Syntax highlighting uses highlight.js classes such as .hljs-keyword, .hljs-string, .hljs-comment, .hljs-title, .hljs-type, .hljs-property and .hljs-number.

Inline code outside of a block gets a distinct pink background so it stands out in prose.

The monospace stack is:

CSS
font-family: 'JetBrains Mono', 'Fira Code', ui-monospace, SFMono-Regular,
  Menlo, Monaco, 'Courier New', monospace;

With Tailwind Typography

tsx
<EntryContent entry={post} className="prose prose-lg max-w-none" />

In a Tailwind v4 app, import the stylesheet into a cascade layer, so your prose-code: utilities keep winning over its defaults:

CSS
@import '@kookee/sdk/styles/content.css' layer(components);

The layer cuts both ways: prose's own pre styles now also reach inside code blocks. Add this unlayered guard once:

CSS
.kookee-entry-content .kookee-code-block pre {
  margin: 0;
  border-radius: 0;
}

.kookee-entry-content .kookee-code-block pre code {
  background: none;
  padding: 0;
  border: none;
  border-radius: 0;
  font-size: 0.875rem;
}

Custom overrides

The stylesheet reads custom properties, so theme it with variables rather than overriding its selectors:

CSS
:root {
  --kookee-code-bg: #282c34;
  --kookee-code-inline-bg: #e8f0fe;
  --kookee-code-inline-fg: #1a73e8;
}

The code variables are --kookee-code-font, --kookee-code-bg, --kookee-code-header-bg, --kookee-code-inline-bg, --kookee-code-inline-fg and --kookee-code-inline-border. File chips read --kookee-file-chip-bg, --kookee-file-chip-border, --kookee-file-chip-fg, --kookee-file-chip-hover-bg and --kookee-file-chip-muted; in dark mode, set at least the chip background and border, whose defaults are light. The class names above are stable too, if you need to target an element directly.

Was this article helpful?