Published on

What You Need To Create A Markdown Editor With TailwindCSS And AlpineJS With Tailwind CSS

Tags
Markdown Editor with TailwindCSS and AlpineJS

If you are a front-end developer, you have probably heard of Tailwind CSS and AlpineJS. Tailwind CSS is a utility-first CSS framework that allows you to quickly build custom designs without writing any CSS. AlpineJS is a lightweight JavaScript framework that allows you to add interactivity to your web pages without the need for a full-fledged framework like React or Angular.

In this article, we will show you how to create a Markdown editor using Tailwind CSS and AlpineJS. We will explain what Tailwind CSS is, why we are using it, and provide a preview and source code for the Markdown editor.

What is Tailwind CSS?

Tailwind CSS is a utility-first CSS framework that provides a set of pre-defined CSS classes that you can use to style your web pages. The framework is designed to be highly customizable, allowing you to easily modify the default styles or create your own custom styles.

One of the benefits of using Tailwind CSS is that it allows you to write less CSS code. Instead of writing custom CSS for each element on your page, you can use pre-defined classes to style your elements. This can save you a lot of time and make your code more maintainable.

The description of Markdown Editor with TailwindCSS and AlpineJS ui component

The Markdown editor we are creating is a simple web application that allows users to write and preview Markdown text. The editor will have a text area where users can write their Markdown text, and a preview area where they can see the formatted text.

We will be using Tailwind CSS to style the editor and AlpineJS to add interactivity to the preview area. When the user types Markdown text into the text area, AlpineJS will convert the Markdown to HTML and display it in the preview area.

Why use Tailwind CSS to create a Markdown Editor with TailwindCSS and AlpineJS ui component?

There are several reasons why we are using Tailwind CSS to create our Markdown editor:

  1. Tailwind CSS provides a set of pre-defined CSS classes that we can use to style our editor. This saves us time and makes our code more maintainable.
  2. Tailwind CSS is highly customizable, allowing us to modify the default styles or create our own custom styles.
  3. Tailwind CSS is designed to be responsive, ensuring that our editor looks good on all devices.

The preview of Markdown Editor with TailwindCSS and AlpineJS ui component

Free download of the Markdown Editor with TailwindCSS and AlpineJS's source code

The source code of Markdown Editor with TailwindCSS and AlpineJS ui component

<!-- This is an example component -->
<div>
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Markdown Editor with Codemirror and AlpineJS</title>
        <link rel="stylesheet" href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" />
        <link rel="stylesheet" href="https://unpkg.com/@tailwindcss/[email protected]/dist/typography.min.css"/>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/lib/codemirror.min.css" />
        <link rel="preconnect" href="https://fonts.gstatic.com">
        <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet">
        <style>
            html { 
                scroll-behavior: smooth; 
                font-family: 'Space Grotesk', sans-serif;
            }
            .cursive {
                font-family: 'Nanum Pen Script', cursive;
            }
            [x-cloak] { display: none; }

            .CodeMirror-focused {   
                border-radius: .375rem;
                outline: 2px solid transparent;
                outline-offset: 2px;
                --tw-ring-opacity: 0.5;
                --tw-ring-color: rgba(199, 210, 254, var(--tw-ring-opacity));
                --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
                --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);
                box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
            }
            .CodeMirror {
                padding: 0.75rem;
                font-family: inherit;
                font-size: inherit;
                border-bottom-left-radius: .375rem;
                border-bottom-right-radius: .375rem;
                --tw-border-opacity: 1;
                border: 1px solid rgba(209, 213, 219, var(--tw-border-opacity));
            }
            .CodeMirror.CodeMirror-focused {
                --tw-border-opacity: 1;
                border-color: rgba(165, 180, 252, var(--tw-border-opacity));
            }

            .cm-s-default .cm-header,
            .cm-s-default .cm-variable-2 {
                color: rgb(31, 41, 55);
            }
        </style>
    </head>
    <body class="bg-gray-50 antialiased">
        <div class="px-4 max-w-4xl mx-auto min-h-screen py-12">

            <div class="text-3xl lg:text-4xl font-bold tracking-tight mb-4 text-center">
                <span class="bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-green-400 ">
                Markdown Editor with Codemirror and AlpineJS
                </span>
            </div>
        
            <div
                x-data="markdown()"
                x-init="
                    convertHtmlToMarkdown();
                    codeMirrorEditor = CodeMirror.fromTextArea($refs.input, {
                        mode: 'markdown',
                        theme: 'default',
                        lineWrapping: true
                    });

                    codeMirrorEditor.setValue(content);
                    codeMirrorEditor.setSize('100%', height);
                    setTimeout(function() {
                        codeMirrorEditor.refresh();
                    }, 1);

                    codeMirrorEditor.on('change', () => content = codeMirrorEditor.getValue())
                "
                class="relative"
                x-cloak
            >
                <div class="bg-gray-50 border border-b-0 border-gray-300 top-0 left-0 right-0 block rounded-t-md">
                    <button type="button" class="py-2 px-4 inline-block text-gray-400 font-semibold" :class="{ 'text-indigo-600': tab === 'write' }" x-on:click.prevent="tab = 'write'; showConvertedMarkdown = false">Write</button>
                    <button type="button" class="py-2 px-4 inline-block text-gray-400 font-semibold" :class="{ 'text-indigo-600': tab === 'preview' && showConvertedMarkdown === true }" x-on:click.prevent="tab = 'preview'; convertedMarkdown()">Preview</button>
                </div>

                <div x-show="! showConvertedMarkdown">
                    <div>
                        <textarea 
                            id="{{ $id }}" 
                            x-ref="input" 
                            x-model.debounce.750ms="content" 
                            class="hidden"
                            name="content"
                        ></textarea>
                    </div>
                </div>

                <div x-show="showConvertedMarkdown">
                    <div x-html="convertedContent" class="w-full prose max-w-none prose-indigo leading-6 rounded-b-md shadow-sm border border-gray-300 p-5 bg-white overflow-y-auto" :style="`height: ${height}; max-width: 100%`"></div>
                </div>
            </div>

            <div class="mt-6 text-gray-500 text-sm text-center">Created by <a class="text-indigo-500 underline" href="https://twitter.com/mithicher">@mithicher</a>.</div>
        </div>

        <script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/codemirror.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/mode/markdown/markdown.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/turndown.min.js"></script>
        <script src="https://unpkg.com/[email protected]/lib/marked.js"></script>
        <script>
            function markdown() {
                return {
                    height: '500px',
                    tab: 'write',
                    content: '',
                    showConvertedMarkdown: false,
                    convertedContent: '',
                    convertedMarkdown() {
                        this.showConvertedMarkdown = true;
                        this.convertedContent = marked(this.content, { sanitize: true });
                    },
                    convertHtmlToMarkdown() {
                        turndownService = new TurndownService({
                            headingStyle: 'atx',
                            codeBlockStyle: 'fenced'
                        });

                        this.content = turndownService.turndown(`
                            <h1 id="sample-markdown">Sample Markdown</h1>
                            <p>This is some basic, sample markdown.</p>
                            <h2 id="second-heading">Second Heading</h2>
                            <ul>
                            <li>Unordered lists, and:<ol>
                            <li>One</li>
                            <li>Two</li>
                            <li>Three</li>
                            </ol>
                            </li>
                            <li>More</li>
                            </ul>
                            <blockquote>
                            <p>Blockquote</p>
                            </blockquote>
                            <p>And <strong>bold</strong>, <em>italics</em>, and even <em>italics and later <strong>bold</strong></em>. Even <del>strikethrough</del>. <a href="https://markdowntohtml.com">A link</a> to somewhere.</p>
                            <p>And code highlighting:</p>
                            <pre><code class="lang-js"><span class="hljs-keyword">var</span> foo = <span class="hljs-string">'bar'</span>;

                            <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">baz</span><span class="hljs-params">(s)</span> </span>{
                            <span class="hljs-keyword">return</span> foo + <span class="hljs-string">':'</span> + s;
                            }
                            </code></pre>
                            <p>Or inline code like <code>var foo = &#39;bar&#39;;</code>.</p>
                            <p>Or an image of bears</p>
                            <p><img src="http://placebear.com/200/200" alt="bears"></p>
                            <p>The end ...</p>
                        `);
                    }
                }
            }
        </script>
    </body>
    </html>
</div>

How to create a Markdown Editor with TailwindCSS and AlpineJS with Tailwind CSS?

To create our Markdown editor, we will be using HTML, Tailwind CSS, and AlpineJS. Here are the steps to create the editor:

  1. Create a new HTML file and add a text area and a preview area to the page.
  2. Add the necessary Tailwind CSS classes to style the text area and preview area.
  3. Add AlpineJS to the page and create a new component that will handle the conversion of Markdown to HTML.
  4. Bind the text area to the AlpineJS component and update the preview area whenever the user types in the text area.

Here is the code for our Markdown editor:

<!DOCTYPE html>
<html>
  <head>
    <title>Markdown Editor</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css">
  </head>
  <body class="bg-gray-100">
    <div class="container mx-auto py-4">
      <h1 class="text-2xl font-bold mb-4">Markdown Editor</h1>
      <div class="flex">
        <div class="w-1/2 pr-4">
          <textarea class="w-full h-64 p-2 border rounded" x-model="markdown" placeholder="Type your Markdown here..."></textarea>
        </div>
        <div class="w-1/2 pl-4">
          <div class="p-2 border rounded" x-html="preview"></div>
        </div>
      </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/alpine.js"></script>
    <script>
      Alpine.component('markdown', {
        data() {
          return {
            markdown: '',
            preview: ''
          }
        },
        watch: {
          markdown() {
            this.preview = marked(this.markdown);
          }
        }
      });
    </script>
  </body>
</html>

Conclusion

In this article, we showed you how to create a Markdown editor using Tailwind CSS and AlpineJS. We explained what Tailwind CSS is, why we are using it, and provided a preview and source code for the Markdown editor.

Tailwind CSS and AlpineJS are powerful tools that can help you create beautiful and interactive web applications. By using these tools, you can save time and create more maintainable code.