- Lab
-
Libraries: If you want this lab, consider one of these libraries.
- Core Tech
Guided: Build a Markdown Previewer in Svelte
In this Guided Code Lab you will learn the basics of Svelte, an increasingly popular JavaScript front-end framework. By building a Markdown previewer you will learn all the basics on Svelte, including how to write a component, add reactivity, and share state between components.
Lab Info
Table of Contents
-
Challenge
Introduction
In this Guided Code Lab you will build a basic Markdown previewer using Svelte. It will have a straightforward layout featuring an input area where users can enter Markdown and a live preview area that dynamically displays the corresponding HTML output.
Svelte is a modern frontend framework that is unique in its approach to building user interfaces. Unlike traditional frameworks like React, Angular, or Vue, which use a virtual DOM to track changes, Svelte shifts much of the work to compile-time. This results in faster and more efficient applications, as Svelte compiles your code to highly optimized vanilla JavaScript at build time.
Svelte is gaining popularity for a few reasons:
- Ease of Learning: With less boilerplate and a straightforward approach, Svelte is easier to grasp for beginners.
- Performance: Due to compile-time optimizations, Svelte applications can be more performant, especially for smaller projects.
- Readability and Maintenance: Svelte's syntax is clean and easy to understand, promoting maintainability.
Because this environment does not have internet access this project has already been scaffolded for you using Vite, required assets have been downloaded, and unneeded files have been removed. (Picnic CSS) has also been added to provide basic styling of native HTML elements.
Steps taken to set up the project
# Create a starter Svelte project pnpm create vite@latest # Install marked pnpm i marked # Remove files and folders that will not be used rm -rf .vscode/ public/vite.svg src/assets/ src/app.css src/lib/Counter.svelte README.md # Download a CSS stylesheet to public/ wget https://raw.githubusercontent.com/franciscop/picnic/master/picnic.min.css -P public/ # Create files for the two Svelte components that will be used touch src/lib/{MarkdownPreview,MarkdownEditor}.svelte # Delete everything from the App component > src/App.svelte # Update the title of index.html # Import the Picnic CSS stylesheet instead of vite.svg # Remove import of app.css sed -i 's/<title>.*<\/title>/<title>Svelte Markdown Previewer<\/title>/' index.html sed -i '/vite.svg/c\<link rel="stylesheet" href="/picnic.min.css">' index.html sed -i '/app\.css/d' src/main.jsThere are some additional packages and changes that are not reflected in the preceding code. These exist to facilitate task validation in this Guided Code Lab and are not relevant to the learning objectives.
info> In the terminal, run
pnpm dev --hostto start a dev server. The application will be available, with hot module replacement, at {{localhost:5173}}. Open this URL in a different tab so you can observe your changes in real time.The completed components for this application are available for your reference in the
solutiondirectory. -
Challenge
Components
Svelte's syntax is a superset of HTML, enhancing the native web technologies — HTML, CSS, and JavaScript — with features that help give both users and developers a better experience.
Svelte components encapsulate HTML, CSS, and JavaScript in a single
.sveltefile with three optional sections: ascriptblock containing JavaScript, HTML markup, and astyleblock containing CSS that will automatically be scoped to the component at compile time. Components can be nested by importing them in thescriptblock (import Example from './Example.svelte') and then including them as if they are an HTML element:<Example />. In your app you will see the three headings andtextareainput.You can visualize Svelte scoping CSS to each component by adding some styles for
h2inMarkdownPreview. Notice how any styles you add don't affect the Markdown Preview heading even though typically CSS would affect allh2elements on the page. -
Challenge
Reactivity in Svelte
Adding reactivity to Svelte components is extremely simple: declare a variable and then reference it in the HTML markup by wrapping it in
{ }. Any time a variable is assigned — or reassigned — the UI will update accordingly.For example, declaring
let namein thescriptblock of your component will allow you to reference the value ofnamein the HTML markup:<h1>{name}</h1>. When you reassign this variable then theh1element will update accordingly.info> Because the Svelte compiler depends on assignment to determine when to update the UI, mutating a variable may not work as intended. For instance, using
.push()on an array will not work trigger an update. You will need to assign the variable to itself:animals = animals.push("cat"). Now you need to add an event handler to update the value of themarkdownas a user types in thetextareaelement.The hard way to do this would be to assign
value={markdown}and then add anonchangehandler to assign the value ofevent.target.valueto themarkdownvariable. And you would also want akeydownevent listener sinceonchangeis only fired after thetextarealoses focus.The Svelte way to do this is to add
bind:value={markdown}and let Svelte do the menial work.This directive allows a two way flow of data to ensure the value of
textareais always in sync with the value ofmarkdown. info> Since this component only has one input you can write even less code by renamingmarkdowntovalueand then addingbind:value. (Note: The rest of this Code Lab will assume the variable is still namedmarkdown) Your app will look the same as last step, but if you want to see your work in action, add{markdown}toMarkdownEditorand watch it update as you type into the input. -
Challenge
Properties
Since this application will need to share the value of
markdownbetween multiple components, you will need to do some refactoring. In this case, the simplest solution is to haveAppmanage the value and share it with both children components by passingmarkdownas a property, often called props.To create a prop in a component export a variable:
export let greeting. Consumers can now pass a value:<UserProfile name={name}>.info> If that looks redundant, Svelte agrees. Since the variable being passed shares a name with the prop, you can wrap it in curly braces:
<UserProfile {name}>. If you passmarkdownto MarkdownEditor the value of thetextareawill initially be set correctly, but when you type the value ofmarkdownwill not update because props are a one-way data flow by default.Like with the
textareain MarkdownEditor, you can bind the value of a variable to create a two-way connection:<UserProfile bind:name>. Now in your app you can see the Markdown Preview section update as you type in thetextareainput. -
Challenge
Rendering the HTML
Now that your app is sharing the
markdownvariable with all the components that need it, you can work on getting the preview working.Add
{markdown}right below theh2element and you will see it updates in real time as you type in thetextarea. You can use any appropriate JavaScript library to convert this Markdown into HTML markup, but in this case you will usemarked. You should now see HTML code rendered in the Markdown Preview section of the application. To have Svelte to render this text as actual HTML elements on the page you can use a special tag.danger> Svelte does not sanitize expressions when using this tag. This means it will render all HTML which can be a serious risk in an untrusted environment. Your app now renders HTML as you type Markdown!
-
Challenge
Next Steps
You now have a real-time markdown previewer built in Svelte!
If you want to keep exploring Svelte, here are a few things you might consider:
- How can you change the style of the component based on its state? (style:property)
- This application updates the page in real time, but users of assistive technologies like screen readers may not be aware of these changes. How can you use an ARIA live region to ensure all users have a good experience using this application?
- Currently the
MarkdownPreviewcomponent is blank when themarkdownvariable isundefined. How can you use a logic block or slot to provide a default state to the component? - How can you use a Svelte store to share the value of
markdownacross components, even deeply nested ones, without needing to manage it in theAppcomponent? - What would the process be to sanitize the input before rendering it with
@html? - Refreshing the page clears the input. How can you persist this value across a page refresh?
About the author
Real skill practice before real-world application
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Learn by doing
Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.
Follow your guide
All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.
Turn time into mastery
On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.