HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<div id="app" class="rounded-lg">
<!-- Swap the order here -->
<editable-textarea ref="editor">
<resizable-textarea>
<textarea
rows="1"
cols="40"
class="resize-none outline-0 m-4 mb-2"
>Nice, Mrs Pancakes. Real nice.
Aw, geez. I am Mr. Booby Buyer.
I'll buy those boobies for 25 schmeckles!
It's called carpe diem Morty.
Look it up.</textarea>
</resizable-textarea>
</editable-textarea>
<div class="bg-grey-light w-100 px-4 py-2 rounded-b-lg">
<button @click="wrapWith('**')" class="border border-grey px-2 py-1 rounded hover:bg-grey outline-0 text-grey-darkest mr-1">
<svg class="w-6 h-6 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M304.793 243.891c33.639-18.537 53.657-54.16 53.657-95.693 0-48.236-26.25-87.626-68.626-104.179C265.138 34.01 240.849 32 209.661 32H24c-8.837 0-16 7.163-16 16v33.049c0 8.837 7.163 16 16 16h33.113v318.53H24c-8.837 0-16 7.163-16 16V464c0 8.837 7.163 16 16 16h195.69c24.203 0 44.834-1.289 66.866-7.584C337.52 457.193 376 410.647 376 350.014c0-52.168-26.573-91.684-71.207-106.123zM142.217 100.809h67.444c16.294 0 27.536 2.019 37.525 6.717 15.828 8.479 24.906 26.502 24.906 49.446 0 35.029-20.32 56.79-53.029 56.79h-76.846V100.809zm112.642 305.475c-10.14 4.056-22.677 4.907-31.409 4.907h-81.233V281.943h84.367c39.645 0 63.057 25.38 63.057 63.057.001 28.425-13.66 52.483-34.782 61.284z"/></svg>
</button>
<button @click="wrapWith('*')" class="border border-grey px-2 py-1 rounded hover:bg-grey outline-0 text-grey-darkest mr-1">
<svg class="w-6 h-6 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M204.758 416h-33.849l62.092-320h40.725a16 16 0 0 0 15.704-12.937l6.242-32C297.599 41.184 290.034 32 279.968 32H120.235a16 16 0 0 0-15.704 12.937l-6.242 32C96.362 86.816 103.927 96 113.993 96h33.846l-62.09 320H46.278a16 16 0 0 0-15.704 12.935l-6.245 32C22.402 470.815 29.967 480 40.034 480h158.479a16 16 0 0 0 15.704-12.935l6.245-32c1.927-9.88-5.638-19.065-15.704-19.065z"/></svg>
</button>
<button @click="wrapWith('~~')" class="border border-grey px-2 py-1 rounded hover:bg-grey outline-0 text-grey-darkest">
<svg class="w-6 h-6 fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.837 0-16-7.163-16-16v-32c0-8.837 7.163-16 16-16h480c8.837 0 16 7.163 16 16v32c0 8.837-7.163 16-16 16zm-214.666 16c27.258 12.937 46.524 28.683 46.524 56.243 0 33.108-28.977 53.676-75.621 53.676-32.325 0-76.874-12.08-76.874-44.271V368c0-8.837-7.164-16-16-16H113.75c-8.836 0-16 7.163-16 16v19.204c0 66.845 77.717 101.82 154.487 101.82 88.578 0 162.013-45.438 162.013-134.424 0-19.815-3.618-36.417-10.143-50.6H281.334zm-30.952-96c-32.422-13.505-56.836-28.946-56.836-59.683 0-33.92 30.901-47.406 64.962-47.406 42.647 0 64.962 16.593 64.962 32.985V136c0 8.837 7.164 16 16 16h45.613c8.836 0 16-7.163 16-16v-30.318c0-52.438-71.725-79.875-142.575-79.875-85.203 0-150.726 40.972-150.726 125.646 0 22.71 4.665 41.176 12.777 56.547h129.823z"/></svg>
</button>
</div>
</div>
* {
margin: 0;
padding: 0;
}
html, body {
height:100%;
font-family: system, helvetica;
}
body {
display: flex;
align-items: center;
justify-content: center;
background-color: #1D1F20;
background: url('https://res.cloudinary.com/lorisleiva/image/upload/v1527763253/backgrounds/11.jpg') center;
background-size: cover;
}
#app {
background-color: white;
box-shadow: 2px 2px 5px rgba(0,0,0,0.5)
}
.outline-0 {
outline: 0;
}
.outline-0:focus {
outline: 0;
}
/**
* Component script.
*/
Vue.component('editable-textarea', {
methods: {
getContent () {
return {
text: this.$el.value,
start: this.$el.selectionStart,
end: this.$el.selectionEnd,
}
},
updateContent (text, start, end) {
this.$el.value = text
triggerEvent(this.$el, 'input')
this.$el.selectionStart = start
this.$el.selectionEnd = end
this.$el.focus()
return text
},
wrapWith (pattern, placeholder) {
let { text, start, end } = this.getContent()
let { before, selection, after } = cutTextWithSelection(text, start, end)
let wrappedContent = selection || placeholder || ''
// Exception for bold and italic
let keepItalicPattern = pattern === '*'
&& _.endsWith(before, '**') && ! _.endsWith(before, '***')
&& _.startsWith(after, '**') && ! _.startsWith(after, '***')
let removePattern = _.endsWith(before, pattern)
&& _.startsWith(after, pattern)
&& ! keepItalicPattern
before = removePattern ? before.slice(0, - pattern.length) : before + pattern
after = removePattern ? after.slice(pattern.length) : pattern + after
return this.updateContent(
before + wrappedContent + after,
before.length,
before.length + wrappedContent.length,
)
},
},
render () {
return this.$slots.default[0]
},
});
Vue.component('resizable-textarea', {
methods: {
resizeTextarea (event) {
event.target.style.height = 'auto'
event.target.style.height = (event.target.scrollHeight) + 'px'
},
},
mounted () {
this.$nextTick(() => {
this.$el.setAttribute('style', 'height:' + (this.$el.scrollHeight) + 'px;overflow-y:hidden;')
})
this.$el.addEventListener('input', this.resizeTextarea)
},
beforeDestroy () {
this.$el.removeEventListener('input', this.resizeTextarea)
},
render () {
return this.$slots.default[0]
},
});
/**
* Start the VueJS application.
*/
new Vue({
el: '#app',
methods: {
wrapWith (pattern) {
return this.$refs.editor.wrapWith(pattern)
}
},
});
/**
* Helper functions.
*/
function cutTextWithSelection (text, start, end) {
return {
before: text.substring(0, start),
selection: text.substring(start, end),
after: text.substring(end, text.length),
}
}
function triggerEvent (el, type) {
if ('createEvent' in document) {
// modern browsers, IE9+
var e = document.createEvent('HTMLEvents')
e.initEvent(type, false, true)
el.dispatchEvent(e)
} else {
// IE 8
var e = document.createEventObject()
e.eventType = type
el.fireEvent('on'+e.eventType, e)
}
}
Also see: Tab Triggers