Here’s why Prefill Embeds are useful: say you have a blog or documentation site displaying important bits of code within <pre><code> tags. Perhaps you need to show a bit of HTML, CSS, or JavaScript. Here’s an example bit of HTML you might show:

<div class="module">
  <h3>Module Title</h3>
  <p>This little piggy went to market.</p>
</div>

CodePen Prefill Embeds are designed to render that code for you in a safe and isolated environment to help your users see, understand, and play with it more easily.

You keep the code on your own site or repo, 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 very 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-prefill 
  data-height="400" 
  data-theme-id="1"
  data-default-tab="html,result" 
>
<pre data-lang="html">
  &lt;div class="module"&gt;
    &lt;h3&gt;Module Title&lt;/h3&gt;
    &lt;p&gt;This little piggy went to market.&lt;/p&gt;
  &lt;/div&gt;
</pre>
</div>
<script async src="https://public.codepenassets.com/embed/index.js"></script>

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": "&lt;meta name=&#x27;viewport&#x27; content=&#x27;width=device-width, initial-scale=1&#x27;&gt;",
    "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">
&lt;div id="root"&gt;&lt;/div&gt;
  </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 &lt;div class="module"&gt;
      &lt;h1&gt;
        Hello, {this.props.name}
      &lt;/h1&gt;
      &lt;p&gt;It's a good day to build websites.&lt;/p&gt;
    &lt;/div&gt;;
  }
}
ReactDOM.render(
  &lt;Welcome name="Chris"&gt;&lt;/Welcome&gt;,
  document.getElementById('root')
);
  </pre>
</div>
<script async src="https://public.codepenassets.com/embed/index.js"></script>

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

Like all our embeds, 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.

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"
  }
>

Here’s are the possible option/values:

optionvalueexampledefault
"title"string“My Pen”blank
"description"Markdown string“It does lots of cool things like spin and blink.”blank
"head"escaped HTML“<meta name=&#x27;viewport&#x27; content=&#x27;width=device-width, initial-scale=1&#x27;>”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

There are more data-* attributes that control other things, here’s the others:

data-attributevalueexampledefault
data-heightInteger“400”“300”
data-theme-idInteger or keyword“13289”, “light”, or “dark”no value, default gray theme
data-editableBoolean“true”“false”
data-default-tabString“html,result”“result”
data-previewBoolean“true”“false”

What goes on the <pre> blocks

HTML blocks are like this:

<pre data-lang="html">
  <!-- *Escaped* HTML goes in here. -->
</pre>

The data-lang can be: html, slim, haml, markdown, or pug

CSS blocks are like this:

<pre data-lang="css" data-options-autoprefixer="true">
</pre>

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>

The data-lang values can be js, babel, typescript, coffeescript, or livescript. Note that in order to us JSX you’ll need to use babel, and you’ll need to escape those angle brackets.

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>
let button = document.querySelector('.enhance-me');
button.addEventListener('click', e => {

  // you could also `fetch` the ei.js script in here.

  // The API for looking for and creating embeds
  window.__CPEmbed(".codepen-later");
});
Was this article helpful?
YesNo