Prefill Embeds are a special type of Embedded Pen where the code used in the Pen is in the embed HTML itself. Here’s an example of why that is useful: say you have a blog or documentation site displaying important bits of code within <pre><code> tags. Here’s an example bit of HTML you might want to show:
<div class="module">
<h3>Module Title</h3>
<p>This little piggy went to market.</p>
</div>Code language: HTML, XML (xml)
CodePen Prefill Embeds are designed to render the code for you in a safe, isolated environment, making it easier for your users to see, understand, and play with it.
You keep the code on your own site or repo, and we help you display and run it. In the demo below, we’re passing in that HTML and also some CSS to style it:
<div class="module"> <h3>Module Title</h3> <p>This little piggy went to market.</p> </div>
$gray: #ccc;
body {
background: $gray;
margin: 0;
padding: 1rem;
}
.module {
background: white;
padding: 1rem;
border-radius: 4px;
border: 1px solid #999;
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.25);
h1 {
margin: 0 0 1rem 0;
}
}The embed code is easy to work with. You leave your <pre> blocks on the page (progressive enhancement! SEO! RSS friendly!), then wrap them in a <div> with attributes that control the embed, like this:
<div
class="codepen"
data-version="2"
data-prefill
data-height="400"
data-theme-id="1"
data-default-tab="html,result"
>
<pre data-lang="html">
<div class="module">
<h3>Module Title</h3>
<p>This little piggy went to market.</p>
</div>
</pre>
</div>
<script async src="https://public.codepenassets.com/embed/index.js"></script>Code language: HTML, XML (xml)
You can pass in a block of HTML, CSS, and JavaScript (all optional), and each supports all of the relevant preprocessors for those languages that CodePen supports. (e.g. Markdown, SCSS, Babel, etc.) Prefill embeds also support all of the options regular Embedded Pens do, like themes, setting the default tabs, and external resources.
Here’s an example with one possible configuration of a complete set of options, including using preprocessors, setting metadata, and loading external resources:
<div id="root"></div>
$gray: #ccc;
body {
background: $gray;
margin: 0;
padding: 1rem;
}
.module {
background: white;
padding: 1rem;
border-radius: 4px;
border: 1px solid #999;
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.25);
h1 {
margin: 0 0 1rem 0;
}
}
class Welcome extends React.Component {
render() {
return <div class="module">
<h1>
Hello, {this.props.name}
</h1>
<p>It's a good day to build websites.</p>
</div>;
}
}
ReactDOM.render(
<Welcome name="Chris"></Welcome>,
document.getElementById('root')
);
Here’s the HTML that makes that happen:
<div
class="codepen"
data-prefill='{
"title": "React Basics Demo",
"description": "Shows how to use React and React DOM to render a module with props onto the page",
"tags": ["react", "react-docs-demo"],
"html_classes": ["loading", "no-js"],
"head": "<meta name='viewport' content='width=device-width, initial-scale=1'>",
"stylesheets": "https://unpkg.com/normalize.css@8.0.1/normalize.css",
"scripts": ["https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js", "https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"]
}'
style="height: 400px; overflow: auto;"
data-height="400"
data-theme-id="31205"
data-default-tab="js,result"
data-editable="true"
>
<pre data-lang="html">
<div id="root"></div>
</pre>
<pre data-lang="scss">
$gray: #ccc;
body {
background: $gray;
margin: 0;
padding: 1rem;
}
.module {
background: white;
padding: 1rem;
border-radius: 4px;
border: 1px solid #999;
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.25);
h1 {
margin: 0 0 1rem 0;
}
}
</pre>
<pre data-lang="babel">
class Welcome extends React.Component {
render() {
return <div class="module">
<h1>
Hello, {this.props.name}
</h1>
<p>It's a good day to build websites.</p>
</div>;
}
}
ReactDOM.render(
<Welcome name="Chris"></Welcome>,
document.getElementById('root')
);
</pre>
</div>
<script async src="https://public.codepenassets.com/embed/index.js"></script>Code language: HTML, XML (xml)
Note the very special encoding for head value. You’ll need to encode any special characters passed there, including angle brackets and, because it needs to be valid JSON, encoded single quotes within the HTML.
What goes on the wrapper element
We rely on a class="codepen" on a wrapper element to enhance that element into a CodePen Embed. For Prefill Embeds, you control some of that with a variety of data-* attributes.
| data-attribute | value | example | default |
|---|---|---|---|
data-height | Integer | “400” | “300” |
data-theme-id | Integer or keyword | “13289” (specific theme) “-2” (dark theme) “-3” (light theme) | no value, default gray theme |
data-editable | Boolean | “true” | “false” |
data-default-tab | String | “html,result” | “result” |
data-preview | Boolean | “true” | “false” |
data-version | Integer | 2 | unused |
The main required one for prefill embeds is data-prefill, which can be just that, or can have the value of a JSON string to send in additional code and options.
<div
class="codepen"
data-prefill={
"option": "value"
}
>Code language: JavaScript (javascript)
Here are the possible option/values:
| option | value | example | default |
|---|---|---|---|
"title" | string | “My Pen” | blank |
"description" | Markdown string | “It does lots of cool things like spin and blink.” | blank |
"head" | escaped HTML | “<meta name='viewport' content='width=device-width, initial-scale=1'>” | blank |
"tags" | string (one) or array (multiple) | [“react”, “react-docs-demo”] | none |
"html_classes" | string (one) or array (multiple) | [“loading”, “no-js”] | none |
"stylesheets" | URL string (one) or array of URLs (multiple) | “https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css” | none |
"scripts" | URL string (one) or array of URLs (multiple) | [“https://website.com/script-1.js”, “https://website.com/script-2.js”] | none |
What goes on the <pre> blocks
HTML blocks are like this:
<pre data-lang="html">
<!-- *Escaped* HTML goes in here. -->
</pre>Code language: HTML, XML (xml)
The data-lang can be: html, markdown, pug, or nunjucks.
CSS blocks are like this:
<pre data-lang="css" data-options-autoprefixer="true">
</pre>Code language: HTML, XML (xml)
The data-lang values can be css, scss, sass, less, stylus, and postcss. Note the extra data-options-autoprefixer, which can be set to true if you want to use Autoprefixer.
JavaScript blocks are like this:
<pre data-lang="js">
</pre>Code language: HTML, XML (xml)
The data-lang values can be js, or typescript. To use JSX, you pass in jsx as the value which will automatically enable the Babel block and remember you must escape the angle brackets.
Limitations
Right now, you can only pass in one <pre> of HTML code (which turns into index.html or relevant processor file extension), one <pre> of CSS code (which turns into style.css or relevant processor file extension) and one <pre> of JavaScript code (which turns into style.js or relevant processor file extension). CodePen 2.0 Pens can certainly handle more files, but prefill embeds are limited to these three for now.
While CodePen supports both the 2.0 Editor and Classic Editor, Prefill Embeds work in either. You put data-version="2" on the wrapper element to get a 2.0 version and it’s mostly backwards compatiable. The except is deprecated languages.
What could go wrong?
This is a pretty complicated HTML API! The escaping of code could trip you up. If you’re displaying <pre> blocks of code on your site, you’ve probably got that code escaping thing already handled though. The trick then is making sure that anything you pass as the {} of data-prefill="{}" is valid JSON, as we parse that directly. Probably doesn’t hurt to validate the JSON.
Enhance <pre> blocks into editable embeds on click (or on any other event)
To do this, set up your prefill embeds as you normally would, only don’t use the class name codepen on the wrapping <div>. Instead, you can use something of your choosing, like codepen-later.
Then on whatever action you choose (could be something like a click, or a scroll into view event, some kind of timeout, or whatever you can think of), you call our global API to convert them into embeds. Here’s an example of a button click to load them:
<!-- normal prefill embed code here, except using <div class="codepen-later"> -->
<button class="enhance-me">Enhance Me</button>Code language: HTML, XML (xml)
let button = document.querySelector('.enhance-me');
button.addEventListener('click', e => {
// you could also `fetch` the CodePen embed script in here.
// The API for looking for and creating embeds
window.__CPEmbed(".codepen-later");
});Code language: JavaScript (javascript)