Build a markdown editor-viewer in Svelte
Tags: svelte, javascript, beginners, markdown
Published: 2021-07-22 18:07:02

Before we dive into writing the code, this blog assumes that the reader knows the basics of Svelte(I will anyway explain each line of code).

## What are we building?
- A `textarea` to enter markdown data.
- A `button` clicking on which will show formatted data.

Demo: https://svelte.dev/repl/da8f6dd0b0ad4fada3011a44702d8d68?version=3.40.1

Screencast: https://www.loom.com/share/1809491290b54906a4b990df89ce9fc3


### Step 1:

Let's first create the `textarea` and the `button` and bind the `textarea` to the component.

```js
<script>
	let rawData = '';
</script>

<main class='main-container'>
  <form class='form'>
    <textarea type='text' bind:value={rawData} class='markdown-input' placeholder='Enter your markdown content here...'/>
    <button class='show-btn' on:click={() => ({})}>
      Show Preview
    </button>
  </form>
</main>
```
Here, we have taken a `main` tag with `class='main-container'` and we will use it at the end for styling the UI. The `<textarea type='text' bind:value={rawData} class='markdown-input' placeholder='Enter your markdown content here...'/>` binds the `textarea` with `rawData` which means when we will change the value inside `textarea`, the same value will be updated in `rawData` variable. The `button` for now is not doing anything on click.

## Step 2:
On clicking the button, we want to hide the editor and process the markdown value stored in `rawData` and show it in the UI. To process the markdown, we will use `marked` package which is quite easy to use. We need to conditionally show the rendered markdown only when the `Show Preview` button is clicked, and so we will use Svelte's `if-else` directive.

```js
<script>
	import marked from 'marked';
	
	let rawData = '';
	let preview = false;
	
	function showPreview() {
		preview = true;
	}
</script>

<main class='main-container'>
	{#if preview}
		<div>
			{@html marked(rawData)}
		</div>
	{:else}
		<form class='form'>
			<textarea type='text' bind:value={rawData} class='markdown-input' placeholder='Enter your markdown content here...'/>
			<button class='show-btn' on:click={showPreview}>
			 Show Preview
			</button>
	</form>
	{/if}
</main>
``` 
We have taken `preview` as `false` by default and based on it's value we are conditionally rendering either the `form` or the formatted markdown using `@html marked(rawData)`.
If we only put this `marked(rawData)`, it would render the `html` equivalent of the `markdown` as plain strings. We want the output of `marked(rawData)` to be rendered as `html` so [we will use `@html`  directive](https://svelte.dev/docs#html). 

`showPreview` function get invoked on clicking the `button` which then assigns `preview = true` and hence the UI is re-rendered and the `if` condition is satisfied and hence the preview is shown.

## Step 3:
Let's use the classes assigned in the above steps to style the app.

```js
<script>
	import marked from 'marked';
	
	let rawData = '';
	let preview = false;
	
	function showPreview() {
		preview = true;
	}
</script>

<main class='main-container'>
	{#if preview}
		<div>
			{@html marked(rawData)}
		</div>
	{:else}
		<form class='form'>
			<textarea type='text' bind:value={rawData} class='markdown-input' placeholder='Enter your markdown content here...'/>
			<button class='show-btn' on:click={showPreview}>
			 Show Preview
			</button>
	</form>
	{/if}
</main>


<style>
	.main-container {
		display: flex;
		flex-direction: column;
		padding: 1rem 0.6rem;
		margin: 0;
		height: 100%;
		width: 100%;
	}
	
.form {
		height: 100%;
		width: 95%;
}
	
	.markdown-input {
		width: 100%;
		height: 90%;
		border: unset;
		border: 1px solid #9c9a9a;
		padding: 0.8rem 1rem;
		border-radius: 10px;
		background: transparent;
	}
	
	.markdown-input::placeholder {
		font-size: 1.2rem;
		font-weight: 100;
		font-family: sans-serif;
		letter-spacing: 1px;
	}
	
	.markdown-input:focus {
		outline: unset;
	}
	
	.show-btn {
		width: 100%;
		padding: 0.6rem 1.5rem;
		background: transparent;
		font-weight: 300;
		font-size: 1.5rem;
		border-radius: 10px;
		border: 1px solid #9c9a9a;
	}

</style>
```
We have used vanilla CSS so it would be self-explanatory. 

## Step 4: 
We can make it more intuitive by adding one more enhancement. Currently, once we click on `show preview` we can't go back to **EDIT** mode. Let's add one more function to assign `preview = false` when the preview area is double-clicked. We will rename the `showPreview` to `togglePreview` and assign `preview = !preview`.

```js
<script>
	import marked from 'marked';
	
	let rawData = '';
	let preview = false;
	
	function togglePreview() {
		preview = !preview;
	}
</script>

<main class='main-container'>
	{#if preview}
		<div on:dblclick={togglePreview}>
			{@html marked(rawData)}
		</div>
	{:else}
		<form class='form'>
			<textarea type='text' bind:value={rawData} class='markdown-input' placeholder='Enter your markdown content here...'/>
			<button class='show-btn' on:click={togglePreview}>
			 Show Preview
			</button>
	</form>
	{/if}
</main>
```
`<div on:dblclick={togglePreview}>` invokes `togglePreview` on double-clicking the `div` showing the preview.

That is it! We have built a markdown preview application using Svelte. Hope you like it and learn something new. Do leave your comments and suggestions to keep me motivated.

Thank you all for reading this.