rehype-custom-component
v1.1.1
Published
Rehype plugin to transform custom components into to handle with React
Maintainers
Readme
rehype-custom-component
A modern rehype plugin to transform custom component shortcodes with XML attributes into HTML elements for React integration.
Installation
npm install rehype-custom-component
# or
yarn add rehype-custom-component
# or
pnpm add rehype-custom-componentUsage
This plugin transforms <CustomComponent> shortcodes with standard XML/HTML attributes into custom HTML elements that can be handled by React or other frameworks.
Basic Usage
import { unified } from 'unified';
import rehypeParse from 'rehype-parse';
import rehypeStringify from 'rehype-stringify';
import rehypeCustomComponent from 'rehype-custom-component';
const processor = unified()
.use(rehypeParse)
.use(rehypeCustomComponent)
.use(rehypeStringify);
const input = `<p>Check out this component: <CustomComponent name="button" type="primary" /></p>`;
const result = await processor.process(input);
console.log(String(result));
// Output: <p>Check out this component: <custom-component name="button" type="primary"></custom-component></p>With Markdown
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeCustomComponent from 'rehype-custom-component';
import rehypeStringify from 'rehype-stringify';
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeCustomComponent)
.use(rehypeStringify);
const markdown = `# My Page
Here's a custom component: <CustomComponent name="card" title="Hello" theme="dark" />`;
const result = await processor.process(markdown);Shortcode Format
The plugin recognizes shortcodes with standard XML/HTML attribute syntax:
<CustomComponent name="componentName" attr1="value1" attr2="value2" />Supported Attribute Formats
<!-- Quoted values -->
<CustomComponent name="button" type="primary" />
<!-- Unquoted values -->
<CustomComponent name="icon" size=large />
<!-- Boolean attributes (flags) -->
<CustomComponent name="input" required disabled />
<!-- Mixed attributes -->
<CustomComponent name="card" title="Hello" active priority=high />Multi-line Support
The plugin supports multi-line shortcodes with flexible formatting:
<!-- Standard multi-line -->
<CustomComponent
name="complexComponent"
title="My Title"
theme="dark"
size="large"
/>
<!-- Minimal multi-line -->
<CustomComponent
data="value"
/>Examples
<!-- Simple component -->
<CustomComponent name="button" type="primary" />
→ <custom-component name="button" type="primary"></custom-component>
<!-- Complex component with multiple attributes -->
<CustomComponent name="card" title="Hello" author="John" published />
→ <custom-component name="card" title="Hello" author="John" published></custom-component>
<!-- Component without additional attributes -->
<CustomComponent name="simple" />
→ <custom-component name="simple"></custom-component>
<!-- Component with boolean flags -->
<CustomComponent name="input" required disabled />
→ <custom-component name="input" required disabled></custom-component>Options
tagName
- Type:
string - Default:
'custom-component'
The HTML tag name to use for the generated elements.
.use(rehypeCustomComponent, { tagName: 'my-component' })
// <CustomComponent name="button" type="primary" />
// → <my-component name="button" type="primary"></my-component>matchName
- Type:
string - Default:
'CustomComponent'
The component name to match in the source text.
.use(rehypeCustomComponent, { matchName: 'MyComponent' })
// <MyComponent name="button" type="primary" />
// → <custom-component name="button" type="primary"></custom-component>TypeScript
This package includes TypeScript declarations and supports both CommonJS and ES modules.
import rehypeCustomComponent, { CustomComponentOptions } from 'rehype-custom-component';
const options: CustomComponentOptions = {
tagName: 'my-component'
};React Integration
The generated HTML elements can be easily handled in React:
// Create a custom component handler
const CustomComponentRenderer = ({ name, ...props }) => {
switch (name) {
case 'button':
return <Button {...props} />;
case 'card':
return <Card {...props} />;
case 'icon':
return <Icon {...props} />;
default:
return <div data-unknown-component={name} {...props} />;
}
};
// Register in your MDX or HTML processor
const components = {
'custom-component': CustomComponentRenderer,
// other components...
};
// Usage example with the generated attributes
// <CustomComponent name="button" type="primary" size="large" disabled />
// becomes:
// <Button type="primary" size="large" disabled />Advanced Usage
Custom Component Names
You can configure the plugin to match different component names:
// Match React-style components
.use(rehypeCustomComponent, {
matchName: 'ReactComponent',
tagName: 'react-component'
})
// Match Vue-style components
.use(rehypeCustomComponent, {
matchName: 'VueComponent',
tagName: 'vue-component'
})Processing Pipeline
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeCustomComponent from 'rehype-custom-component';
import rehypeStringify from 'rehype-stringify';
const processor = unified()
.use(remarkParse)
.use(remarkRehype, { allowDangerousHtml: true })
.use(rehypeCustomComponent, {
tagName: 'my-component',
matchName: 'Component'
})
.use(rehypeStringify, { allowDangerousHtml: true });
const markdown = `
# My Document
<Component name="hero" title="Welcome" subtitle="Get started" primary />
Regular markdown content continues here.
`;
const result = await processor.process(markdown);Requirements
- Node.js 16 or higher
- Modern ES6+ environment supporting
matchAll(), nullish coalescing (??), and spread syntax
Features
- ✅ Modern ES6+ implementation with array destructuring and functional programming patterns
- ✅ XML/HTML attribute syntax - familiar and standard
- ✅ Multi-line component support with flexible formatting
- ✅ Boolean attributes for flags and toggles
- ✅ Quoted and unquoted values support
- ✅ Configurable component names and output tag names
- ✅ TypeScript support with full type definitions
- ✅ Zero dependencies except for peer dependencies
License
MIT © Matthieu Conti
Contributing
Issues and pull requests are welcome! Please check the existing issues before creating a new one.
Related
- rehype - HTML processor powered by plugins
- MDX - Markdown for the component era
- unist-util-visit - Utility to visit nodes
