Skip to content
PluginStats

@foldkit/markdown weekly downloads statistics

By foldkit (2 listings) · npm · Vite plugins

Write markdown files, get Foldkit views with live islands.

View on npm Fresh · Oct 28, 2026

@foldkit/markdown has 9,645 recorded weekly downloads on npm, ranking #1010 of 2,644 tracked listings.

Weekly downloads
9,645
Official API · Oct 26, 2026
7-day growth
—
Insufficient history
30-day growth
—
Insufficient history
90-day growth
—
Insufficient history
Rank
#1010
Among tracked npm listings

About @foldkit/markdown

@foldkit/markdown

Write markdown files, get Foldkit views with live islands.

A Vite plugin parses each imported .md file with remark, validates it against an Effect Schema vocabulary, and emits a typed document module. The browser receives data, never a parser. A pure fold renders the document as Foldkit Html, so markdown content participates in the vdom, DevTools, and time travel like any other view.

Install

pnpm add @foldkit/markdown

Setup

Add the plugin to vite.config.ts:

import { defineConfig } from 'vite'

import { markdown } from '@foldkit/markdown/vite'
import { foldkit } from '@foldkit/vite-plugin'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [tailwindcss(), foldkit(), markdown()],
})

Type .md imports by adding the ambient declaration to your tsconfig.json:

{
  "compilerOptions": {
    "types": ["@foldkit/markdown/content"]
  }
}

If you run tests with Vitest, add markdown() with the same options to the plugins in vitest.config.ts as well, so test runs compile and validate .md imports exactly the way the app build does.

Render a document

import { Html, type HtmlBuilder } from 'foldkit/html'

import * as Markdown from '@foldkit/markdown'

import aboutRaw from './content/about.md'
import { type Message } from './message'

const about = Markdown.decodeDocument(aboutRaw)

const view = (h: HtmlBuilder<Message>): Html =>
  h.div([], [Markdown.view(about)])

decodeDocument memoizes on the wire object, so calling it inside a view decodes each module once rather than once per render.

Markdown.view renders every node through unstyled semantic defaults. Restyle any node by overriding its view:

Markdown.view(about, {
  views: {
    Paragraph: (paragraph, content) =>
      h.p([h.Class('leading-relaxed text-stone-700')], content),
    Link: ({ url }, content) =>
      h.a([h.Href(url), h.Class('underline underline-offset-2')], content),
    CodeBlock: ({ value }, occurrenceIndex) =>
      h.pre([h.Id(`code-${occurrenceIndex}`)], [h.code([], [value])]),
  },
})

The CodeBlock view's second argument is its zero-based occurrence index in document order, for deriving stable per-instance identifiers.

Markdown.viewBlocks returns one Html per top-level block instead, for when the blocks should land directly inside your own container element.

Islands

Directives reserve space in the prose for live application views. A leaf directive stands alone; a container directive wraps nested markdown:

The count lives in the Model like everything else on this page.

::Counter{label="Clicks while reading"}

:::Note{tone="calm"}
Islands can wrap _markdown_ too.
:::

Declare each island's attributes as a Schema struct, once, in a module both your Vite config and your views import:

// src/islands.ts
import { Schema } from 'effect'

export const islandAttributes = {
  Counter: Schema.Struct({ label: Schema.optionalKey(Schema.String) }),
  Note: Schema.Struct({ tone: Schema.optionalKey(Schema.String) }),
}

Pass the definitions to the plugin and every directive validates at build time. An unknown island name, an unknown attribute, or an attribute value outside its schema fails the build with the file and line:

import { markdown } from '@foldkit/markdown/vite'

import { islandAttributes } from './src/islands'

markdown({ islands: islandAttributes })

islandsFor pairs the same definitions with typed views: attributes arrive decoded through each island's schema, and the record must cover every declared name. State stays in your Model; the markdown only decides placement. The third argument is the zero-based occurrence of that island name in the document, for identifiers that must be unique per instance, like an h.submodel slotId:

import { Html, type HtmlBuilder } from 'foldkit/html'

import * as Markdown from '@foldkit/markdown'

import { Counter } from './counter'
import { islandAttributes } from './islands'
import { GotCounterMessage, type Message, type Model } from './message'

const postView = (
  model: Model,
  post: Markdown.MarkdownDocument,
  h: HtmlBuilder<Message>,
): Html =>
  Markdown.view(post, {
    islands: Markdown.islandsFor(islandAttributes, {
      Counter: ({ label }, _content, occurrenceIndex) =>
        h.div(
          [],
          [
            h.span([], [label ?? 'Counter']),
            h.submodel({
              slotId: `counter-${occurrenceIndex}`,
              model: model.counter,
              view: Counter.view,
              toParentMessage: message => GotCounterMessage({ message }),
            }),
          ],
        ),
      Note: (_attributes, content) =>
        h.aside([h.Class('rounded border p-4')], content),
    }),
  })

Attribute values are strings on the wire, so transforming field schemas decode past them: Schema.NumberFromString turns ::Chart{height="240"} into height: number. A plain islands record of untyped views (Readonly<Record<string, IslandView>>) also works when you want to skip the schemas.

Frontmatter

Documents can open with a frontmatter block when the plugin is given a schema for it. Declare the fields as a Schema struct, once, in a module both your Vite config and your application import:

// src/postFrontmatter.ts
import { Schema } from 'effect'

export const PostFrontmatter = Schema.Struct({
  title: Schema.String.check(Schema.isNonEmpty()),
  date: Schema.String,
})
import { markdown } from '@foldkit/markdown/vite'

import { PostFrontmatter } from './src/postFrontmatter'

markdown({ frontmatter: PostFrontmatter })
---
title: 'Introducing the blog'
date: 2026-08-01
---

The prose starts here.
```…

Description from the npm listing.

  • foldkit
  • markdown
  • vite-plugin
  • islands
  • mdast

README badge

Show your rank in a README or on your website. The badge updates automatically.

Charts

Images: 30d · 1y · all time · 1600×900 dark

Adoption over time

@foldkit/markdown weekly downloads on npm, last 90 days: 9,645 weekly downloads as of Oct 26, 2026.@foldkit/markdownWeekly downloads on npm · Last 90 days9,645downloads / week8.5K9K9.5K10K10.5K11KJul 28Aug 12Aug 27Sep 11Sep 26Oct 11Oct 26downloads / weekOct 26, 2026 – Oct 26, 2026 · 1 observations · Updated Oct 26, 2026pluginstats.com
@foldkit/markdown weekly downloads on npm, last 90 days: 9,645 weekly downloads as of Oct 26, 2026.

7/30/90-day growth

@foldkit/markdown weekly downloads growth on npm: 7-day growth unavailable, 30-day growth unavailable, 90-day growth unavailable.@foldkit/markdownWeekly downloads growth on npm9,645downloads / week now7-day growthinsufficient historyInsufficient history30-day growthinsufficient historyInsufficient history90-day growthinsufficient historyInsufficient historyGrowth vs. nearest observation to each baseline date · Updated Oct 26, 2026pluginstats.com
@foldkit/markdown weekly downloads growth on npm: 7-day growth unavailable, 30-day growth unavailable, 90-day growth unavailable.

Ranking history

@foldkit/markdown npm ranking history: currently #1010 (by weekly downloads).@foldkit/markdownnpm ranking · by weekly downloads · Last 90 days#1010current rank#1008#1009#1010#1011#1012Jul 30Aug 14Aug 29Sep 13Sep 28Oct 13Oct 28rankOct 28, 2026 – Oct 28, 2026 · 1 observations · Updated Oct 26, 2026pluginstats.com
@foldkit/markdown npm ranking history: currently #1010 (by weekly downloads).

Listing placement

All npm2,642 listings · 133 pages · 1,323 shown · page 55, #2 (overall #1,082)
All npm: every listing in weekly downloads order

Listing placement

Vite plugins275 listings · 14 pages · page 10, #8 (overall #188)
Vite plugins: every listing in weekly downloads order

Filled points are observed values; hollow points come from Internet Archive snapshots of the listing page. Dashed segments span periods with no observations — values between points are not interpolated.

Each band is one page of 20. Weekly downloads on a linear scale. Placement is projected from weekly downloads, so it can differ from the marketplace's own sort order. Hover a dot to see the listing.

Recent observations

Full history (1)
Recent weekly downloads observations for @foldkit/markdown
Date (UTC)Weekly downloadsChange vs. previous
9,645—

Similar npm Vite plugins plugins

All 20 @foldkit/markdown alternatives

Data source

Weekly downloads (trailing 7 complete days) come from the official npm downloads API. Downloads include CI and mirrors and are not equivalent to installs or users. npm publishes no ratings.

Listing: https://www.npmjs.com/package/@foldkit/markdown. First seen Oct 28, 2026; last successful collection Oct 28, 2026. See the methodology.