Tutorials on Svelte

Learn about Svelte from fellow newline community members!

  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL
  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL

Building a Choropleth Map with D3 and Svelte

In this article, we will create a data visualization that displays the ratio of Dunkin’ Donuts locations to Starbucks locations (by state) using D3 and Svelte. Which of America’s largest coffee chains keeps your state awake and ready for the 9-5 workday?Choropleth maps bring data to life. By projecting data onto a map, you can craft a captivating, visual narrative around your data that uncovers geographical patterns and insights. Choropleth maps color (or shade) geographical areas like countries and states based on numeric data values. The intensity of the color represents the magnitude of the data value in a specific geographical area. With a single glance, these colors allow us to easily identify regional hotspots, trends and disparities that are not immediately apparent from raw data. Think about the geographic distribution of registered Democrat and Republican voters across the United States. A state with an overwhelming majority of registered Democrat voters might be colored blue, whereas a state with an overwhelming majority of registered Republican voters might colored red. A state with a single-digit percentage difference between registered Democrat and Republican voters, such as Pennsylvania, would be colored blue purple. On the contrary, a state with a significantly larger ratio of registered Democrat voters to Republican voters, such as California, would be colored a more intense blue. Examining all of the states, you will recognize that registered Democrat voters primarily reside in states in the northeast region and along the western coastline of the United States. Choropleth maps let us answer geographic questions about our data and contextualize our data through the lens of our knowledge of the world. For example, looking at a choropleth map of registered Democrat and Republican voters in the United States on a state basis, it may make evident the differences in the laws and policies enacted across each state. Anyone who can read a map will have zero troubles navigating, understanding and deriving conclusions from choropleth maps. A common method for creating Choropleth maps for the web is D3, a popular JavaScript data visualization library. However, using just D3 to create choropleth maps comes with several downsides: And so, why not delegate the rendering logic to a declarative, UI framework like Svelte? Svelte surgically updates the DOM and produces highly optimized JavaScript code with zero runtime overhead. Additionally, Svelte components consist of three sections — script, styles and markup — to keep logic organized and consistent. By letting Svelte handle the rendering logic and D3 handle the data transformation logic (and difficult mathematical calculations), we can: Below, I'm going to show you how to build a choropleth map with D3 and Svelte. The choropleth map will display the ratio of Dunkin’ Donuts locations to Starbucks locations (by state). States with significantly more Starbucks locations than Dunkin’ Donuts locations will be colored green, and states with significantly more Dunkin’ Donuts locations than Starbucks locations will be colored orange. A legend will be added to map colors to magnitudes of location ratios. By the end of this tutorial, you will have built the following choropleth map: To set up a new Svelte project with Vite and TypeScript , run the command npm init vite . Note : You may generate a new Svelte application with SvelteKit, but this tutorial is only focused on building out a single Svelte component for the choropleth map. Therefore, it’s more preferred to use a lighter template so that you don’t need to mess around with extra project files. To obtain the number of Dunkin’ Donuts and Starbucks locations in those states, visit the following websites: And record the states and their location counts in two CSV files: dunkin_donuts_locations_counts.csv and starbucks_locations_counts.csv . Each CSV’s header row includes titles for two columns: state and count . The delimiter should be a comma. Then, within the public directory, create a data directory and place both CSV datasets in this new directory. To obtain a TopoJSON file of the geometries that represent US states, visit the U.S. Atlas TopoJSON GitHub repository ( https://github.com/topojson/us-atlas ). Then, scroll through the contents of the repository’s [README.md](http://README.md) file and download the states-albers-10m.json file. The state boundaries are drawn based on the 2017 edition of the Census Bureau’s cartographic state boundaries. Unlike the states-10m.json file, the geometries within this file have been projected to fit a 975 x 610 viewport. Once downloaded, rename the file as us_topojson.json and place it within the public/data directory. To create geographic features in an SVG canvas, D3 consumes GeoJSON data. Therefore, why are we downloading a TopoJSON file? TopoJSON is an extension of GeoJSON that eliminates redundancy in geometries via arcs . It’s more compact than GeoJSON (typically 80% smaller than their GeoJSON equivalents), and it preserves and encodes topology. For the choropleth map, it will download a TopoJSON file, not a GeoJSON file, of US states so that the choropleth map does not have to wait long . Then, we will leverage a module, topojson-client , to convert TopoJSON features to GeoJSON features for D3 to work with. For the choropleth map, we will need to install four specific D3 modules and a related module that’s also from the creator of D3: Run the following command to install these D3 modules and their type definitions in the Svelte project. First, delete the src/lib directory and src/app.css file. Then, in src/main.ts , omit the import './app.css' statement at the top of the file. In the src/App.svelte file, clear out the contents of the script, style and markup sections. Within the script section, let’s add the import statement for the <ChoroplethMap /> component and declare two variables: ( src/App.svelte ) Within the style section, let’s add some minor styles to horizontally center the <ChoroplethMap /> component in the <main /> element. ( src/App.svelte ) Note : Styles defined in the <App /> component won’t leak into other Svelte components. Within the <main /> element of the markup section, call the <ChoroplethMap /> component. Also, pass datasets to the datasets prop and colors to the colors prop of the ChoroplethMap /> component, like so: ( src/App.svelte ) Within the src directory, create a new folder named components . This folder will contain any reusable components used in this Svelte application. In this case, there will only be one component in this directory: ChoroplethMap.svelte . Create this file inside of the src/components directory. Within the src/components/ChoroplethMap.svelte file, begin with an empty script section for the <ChoroplethMap /> component: ( src/components/ChoroplethMap.svelte ) At the top of the script section, import several methods from the installed D3 modules: ( src/components/ChoroplethMap.svelte ) Then, declare the datasets and colors props that the <ChoroplethMap /> component currently accepts. Set their default values to empty arrays when no value is passed to either prop. ( src/components/ChoroplethMap.svelte ) d3-fetch comes with a convenient method for fetching and parsing CSV files: csv() . This method accepts, as arguments, a URL to a CSV dataset and a callback function that maps each row’s values to actual data values. For example, since numeric values in a CSV file will initially be represented as strings, they must be parsed as numbers. In our case, we want to parse count as a number. In a Svelte component, we will need to use the onMount lifecycle method to fetch data after the component gets rendered to the DOM for the first time, like so: For us to load both datasets, we can: Note : We’re flattening the returned data so that we can later group the data by state and calculate the location ratio on a per state basis. d3-fetch comes with a convenient method for fetching and parsing JSON files: json() . For the choropleth map, we will only want the method to accept, as an argument, a URL to the TopoJSON file with the geometry collection for US states. We will need to add this line of code to the onMount lifecycle method so that the TopoJSON data gets fetched alongside the CSV data, like so: To convert TopoJSON data to GeoJSON data, we will need to… Add these lines of code to the onMount lifecycle method, like so: Like with any D3 data visualization, you need to define its dimensions . Let’s define the choropleth map’s width, height and margins, like so: In the <ChoroplethMap /> component’s markup section, add an <svg /> element and set its width , height and viewBox using the values from dimensions . Within this <svg /> element, add a <g /> element that will group the <path /> elements that will represent the states and the internal borders between them. Back in the script section of the <ChoroplethMap /> component, create a new geographic path generator via the geoPath() method, like so: path is a function that turns GeoJSON data into a string that defines the path to be drawn for a <path /> element. In other words, this function, when called with stateMesh or a feature object from statesFeatures , will return a string that we can set to the d attribute of a <path /> element to render the internal borders between states or a state respectively. Here, we’ll render the internal borders between states and use an each block to loop over the feature objects in statesFeatures and render the states inside of the <g /> element, like so: Since stateMesh and statesFeatures are declared within the onMount lifecycle method, we’ll have to move the declarations to the top-level of the script section to ensure that these values can be used in the markup section of the <ChoroplethMap /> component. When you run the project in development via npm run dev , you should see a choropleth map that looks like the following: To adjust the fill color of each state by location ratio, first locally declare two variables at the top-level of the script section: Note : <string, string> corresponds to <Range, Output> . The Range generic represents the type of the range data. The Output generic represents the type of the output data (what’s outputted when calling scale() ). Within the onMount lifecycle method, using the d3-array 's rollup() method, group the data by state name, and map each state name to a ratio of Dunkin’ Donuts locations in the state to Starbucks locations in the state. Then, get the maximum location ratio from ratios via D3’s extent() method. Since the method only accepts an array as an argument, you will need to first convert the map to an array via Array.from() . Then, set scale to a linear scale that maps the ratios to colors passed into the colors prop. The max value corresponds to the first color in the colors list, an orange color. Any state that’s colored orange will indicate a higher ratio of Dunkin’ Donuts locations to Starbucks locations. Additionally, any state that’s colored green will indicate a lower ratio of Dunkin’ Donuts locations to Starbucks locations. A 1:1 ratio ( 1 in the domain) denotes an equal number of Dunkin’ Donuts locations to Starbucks locations. Note : A quantized scale would be better suited. However, the domain of scaleQuantize() accepts only two arguments, a minimum and maximum value. This means you cannot define your own threshold values ( scaleQuantize() automatically creates its own threshold values from the provided minimum and maximum values). Within the markup section of the <ChoroplethMap /> component, replace the currently set fill of "green" to scale(ratios.get(feature.properties.name)) . Upon saving these changes, you should see the colors of the states update. Wow, it seems Dunkin’ Donuts keeps the northeast of the US awake! The colors chosen for this data visualization are based on the official branding colors of Dunkin’ Donuts and Starbucks. For folks who might not be familiar with Dunkin’ Donuts and Starbucks official branding colors, let’s create a simple legend for the choropleth map so they know which states have a higher concentration of Starbucks locations and which states have a higher concentration of Dunkin’ Donuts locations. First, let’s locally declare a variable categories that maps datasets to an array that contains only the labels of the datasets. Then, create a new file in the src/components directory: Legend.svelte . This <Legend /> component will accept three props: dimensions , colors and categories . Given that we only want two labels for the legend, one for the first color in colors and one for the last color in colors , we create the labels by setting the first item in labels to categories[0] (”Dunkin’ Donuts”) and the last item in labels to categories[1] (”Starbucks”). Then, we leave the middle three labels undefined. This way, we can render the colors and labels one-to-one in the markup section. ( src/components/Legend.svelte ) Back in the <ChoroplethMap /> component, we can import the <Legend /> component and render it within the <svg /> element like so: Upon saving these changes, you should see the legend appear in the bottom-right corner of the choropleth map. Try customizing the choropleth map with your own location counts data. If you find yourself stuck at any point while working through this tutorial, then feel free to check out the project's GitHub repository or a live demo of this project in the following CodeSandbox: If you want to learn more about building visualizations with D3 and Svelte, then check out the Better Data Visualizations with Svelte course by Connor Rothschild, a partner and data visualization engineer at Moksha Data Studio.

Thumbnail Image of Tutorial Building a Choropleth Map with D3 and Svelte

Building a Bar Chart Race with D3 and Svelte

In this article, we will create a data visualization that animates the changes in the stargazer counts of popular front-end library/framework GitHub repositories over the past 15 years. Which front-end libraries/frameworks currently dominate the web development landscape? Which front-end libraries/frameworks used to dominate web development landscape?Bar chart races make boring bar charts dynamic and fun. Unlike regular bar charts, bar chart races show the growth and decline (the fluctuations) in the relative values of categories over time. Each bar represents a category, and the bar grows or shrinks in length with respect to its corresponding value at a given time and an ever-changing scale. The bars reposition themselves, commonly, in descending order of values. Depending on the maximum number of bars that can be shown in the bar chart race, you may occasionally see a bar drop off at or re-emerge from the bottom of the visualization. Due to the animation aspect of bar chart races (the racing effect created by animated bars), they have become popular in recent years on social media platforms. They turn vast amounts of complex data into a captivating, easy-to-digest medium. Bar chart races reveal trends that emerged or fell off across intervals of time. For example, if you created a bar chart race of browser usage over the 1990s to the present day, then you may initially see the rise of Internet Explorer, followed by its gradual decline as browsers like Chrome and Firefox became dominate forces in the browser market. D3 is great at tracking elements in an animation and animating enter and exit transitions. However, its imperative .join() approach to data-binding and managing enter, update and exit animations separately is not as expressive as Svelte’s declarative approach via reactivity, dynamic attributes (via curly braces) and built-in animation and transition directives. Below, I'm going to show you how to build a bar chart race with D3 and Svelte. The bar chart race will show the rate of growth in each GitHub repository’s stargazer count from April 2009 to the present day. By the end of this tutorial, you will have build the following bar chart race: To set up a new Svelte project with Vite and TypeScript , run the command npm init vite . Note : You may generate a new Svelte application with SvelteKit, but this tutorial is only focused on building out a single Svelte component for the bar chart race. Therefore, it’s more preferred to use a lighter template so that you don’t need to mess around with extra project files. Currently, you cannot query GitHub’s GraphQL API for a GitHub repository’s stargazer counts history. However, there’s an open source project that maintains records of repositories’ stargazer counts through the years: Star History. To get a CSV of historical stargazer counts for a GitHub repository, enter the both the username of the GitHub repository’s author and the name of the GitHub repository, delimited by a / . For example, facebook/react for React.js. Once you’ve clicked on the “View star history” button and waited for the chart to be generated, click on the CSV button to download this data into a CSV file. You can add more GitHub repositories to the chart so that the CSV will contain data for all of these GitHub repositories. For the bar chart race, we will be visualizing the historical stargazer counts for the following repositories: Once downloaded, rename the file as frontend-libraries-frameworks.csv and place it within the public/data directory. Since the data is incomplete, we will be interpolating stargazer counts for unknown dates. Additionally, from the dates, omit the day of week, the time and the time zone from the values of the second column (e.g., Thu Feb 11 2016 12:06:18 GMT-0500 (Eastern Standard Time) → Feb 11 2016 ). At the top of the CSV, add a header row to label the columns: “name,date,value.” For the bar chart race, we will need to install five specific D3 modules: Run the following command to install these D3 modules and their type definitions in the Svelte project. First, delete the src/lib directory and src/app.css file. Then, in src/main.ts , omit the import './app.css' statement at the top of the file. In the src/App.svelte file, clear out the contents of the script, style and markup sections. Within the script section, let’s add the import statement for the <BarChartRace /> component and two variables: ( src/App.svelte ) Within the style section, let’s add some minor styles to horizontally center the <BarChartRace /> component in the <main /> element. ( src/App.svelte ) Note : Styles defined in the <App /> component won’t leak into other Svelte components. Within the <main /> element of the markup section, call the <BarChartRace /> component. Also, pass datasetUrl to the datasetUrl prop and maxBars to the maxBars prop of the <BarChartRace /> component, like so: ( src/App.svelte ) Then, create a types folder under the src directory. Within this folder, create an index.ts file and define and export two interfaces: Record and KeyframeRecord . ( types/index.ts ) We will annotate the records from the raw CSV dataset with Record , and we will annotate the records stored in a “keyframe” (we will cover this later in this tutorial) with KeyframeRecord . Within the src directory, create a new folder named components . This folder will contain any reusable components used in this Svelte application. In this case, there will only be one component in this directory: BarChartRace.svelte . Create this file inside of the src/components directory. Within the src/components/BarChartRace.svelte file, begin with an empty script section for the <BarChartRace /> component: ( src/components/BarChartRace.svelte ) At the top of the script section, import several methods from the installed D3 modules: ( src/components/BarChartRace.svelte ) Then, declare the datasetUrl and maxBars props that the <BarChartRace /> component currently accepts. Additionally, locally declare three variables: ( src/components/BarChartRace.svelte ) d3-fetch comes with a convenient method for fetching and parsing CSV files: csv() . This method accepts, as arguments, a URL to a CSV dataset and a callback function that maps each row’s values to actual data values. All values in the CSV dataset are represented as strings. For the bar chart race, we need to parse value as a number and date as a Date object. To parse date as a Date object, create a parser by calling the timeParse() method with the structure of the stringified date (so that the parser understands how to parse the date string). Since date is formatted as <abbreviated month name> <zero-padded day of the month> <year with century> (e.g., Feb 11 2016 ), we pass the specifier string of "%b %d %Y" to the timeParse() method. In a Svelte component, we will need to use the onMount lifecycle method to fetch data after the component gets rendered to the DOM for the first time, like so: The bar chart race’s animation iterates over a series of keyframes. Each keyframe represents exactly one moment of the bar chart race; it contains data of the GitHub repositories’ stargazer counts at a given date. Because the source dataset from Star History doesn’t contain stargazer counts at every single date from April 2009 (the month of the earliest known stargazer count) to the present day, we will need to interpolate between data points (estimate stargazer counts for unknown dates) to guarantee that there’s enough keyframes to make the animation run smoothly. Every x milliseconds, we can update the animation with the data from the next keyframe until we run out of keyframes, at which point, the animation will stop at the current day stargazer counts for the GitHub repositories. To create these keyframes, we need to: Like with any D3 data visualization, you need to define its dimensions . Let’s define the bar chart race’s width, height and margins, like so: In the <BarChartRace /> component’s markup section, add an <svg /> element and set its width , height and viewBox using the values from dimensions . Within this <svg /> element, add a <g /> element that will group the <rect /> elements that will represent the bars. The x-scale maps a domain of stargazer counts to the horizontal dimensions of the bar chart race. You’re probably wondering why the maximum value of the domain is 1 despite our source dataset shows that the maximum stargazer count is 210,325. This domain serves as a placeholder for the x-scale’s domain. When we’re animating the bar chart race by iterating over the keyframes, we will adjust the x-scale’s domain based on the current keyframe’s data. This way, during the animation, the maximum stargazer count will always span the entire width ( dimensions.width - dimensions.margin.right ) of the bar chart race. On the other hand, the y-scale maps a domain of visible bar indices to the vertical dimension of the bar chart race. The domain specifies 1 more than the maximum number of visible bars since we want to be able to transition between the bottom-most visible bar and the hidden bar beneath it smoothly. Note : <number> corresponds to <Range> . This generic represents the data type of the domain values. Then, define a color scheme. Initialize it as a function that returns “#FFFFFF.” This function will serve as a placeholder function until we actually fetch the CSV dataset, at which point, we can reassign the color scheme to map each GitHub repository to a specific color. Note : _d ensures that the function signature matches the function signature of the function that will override this placeholder function. In the onMount lifecycle method, after fetching the CSV dataset and creating a set of GitHub repository names from the source data, assign a new color scheme that assigns each GitHub repository name to a specific color, like so: To animate the bar chart race, first locally declare a variable keyframeItems at the top-level of the script section: keyframeItems will hold a keyframe’s list of the GitHub repositories and their stargazer counts and ranks. By reassigning this variable for each keyframe, Svelte’s reactivity will automatically update the bars’ widths and positions. Additionally, at the top-level of the script section, call the timeFormat() method with a string that describes how to format the date based on an input Date object. This way, the formatter knows what to output when given an input Date (e.g., “Jul 2023”). In the onMount lifecycle method, once the keyframes have been created, set up a setInterval() function that… Note : In a future tutorial, I will show you how to re-implement this with requestAnimationFrame . Within the <g /> element in the markup section of the <BarChartRace /> component, use an each block to loop over keyframeItems and render a <rect /> for each visible bar. The items are keyed by the GitHub repositories’ names so that Svelte knows not to recreate the bars anytime keyframeItems gets updated and to just continue modifying properties of the existing bars. The in and out directives allow us to control the enter and exit animations of the bars. For example, in corresponds to an enter animation, and out corresponds to an exit animation. To keeps things simple, we’ll have the bar fade out when it exits and fade in when it enters. Finally, add an axis line to show the bars left-aligned and the ticker to the <svg /> element. When you run the project in development via npm run dev , you should see a bar chart race that looks like the following: Try customizing the bar chart race for your own historical count data. If you find yourself stuck at any point while working through this tutorial, then feel free to check out the project's GitHub repository or a live demo of this project in the following CodeSandbox: If you want to learn more about building visualizations with D3 and Svelte, then check out the Better Data Visualizations with Svelte course by Connor Rothschild, a partner and data visualization engineer at Moksha Data Studio.

Thumbnail Image of Tutorial Building a Bar Chart Race with D3 and Svelte

I got a job offer, thanks in a big part to your teaching. They sent a test as part of the interview process, and this was a huge help to implement my own Node server.

This has been a really good investment!

Advance your career with newline Pro.

Only $30 per month for unlimited access to over 60+ books, guides and courses!

Learn More

Building a Word Cloud with D3 and Svelte

In this article, we will create a data visualization that displays the frequency of words in the lyrics of a song under the Billboard Hot 100 list, Vampire, by Olivia Rodrigo, using D3 and Svelte. Which words do you think catapult a song to the Billboard Hot 100 list?When repeated enough times, words become memorable. Anytime you listen to a speech, notice how frequently certain words come up, how the repetition helps you recognize the importance of the speaker’s message. If you happen to only have a transcript of the speech, then you would need to read/skim through paragraphs of text to grasp the essence of the speaker's words and gain a complete understanding of the message being conveyed. With word clouds (also known as tag clouds ), you can visualize the frequency of words. Words are arranged in a cloud-shaped formation, and each word is sized and colored based on its frequency (or importance) in a given text. The more frequently a word appears, the larger (or more intense color-wise) it appears in the word cloud. This makes it easier to visually identify critical keywords and themes in textual content. Simultaneously, word clouds capture and summarize the essence of textual content in a single glance. Whether you are interested in seeing what trending topics are being discussed in online communities or what words leaders use to inspire their nations, a word cloud offers a clear window into any textual content. There’s a D3 module that’s available for generating word clouds: d3-cloud . This module automatically takes a mapping of words and their frequencies and determines how to properly size and position them in a word cloud with minimal collisions. However, since the pure D3 implementation of a word cloud involves appending an SVG <text /> element, one by one, each time a word gets processed: What happens if we want to update the word cloud using another set of words? Rather than having to manually manage the DOM using D3’s imperative API (i.e., manually removing all of the previous SVG <text /> elements, re-appending new SVG <text /> elements, etc.), we can let Svelte render elements to the DOM and keep the DOM in sync with our data via reactivity . This way, anytime our data changes, Svelte automatically updates the DOM accordingly. In Svelte, all assignments are reactive. If we wanted to mark any number of top-level statements reactive, like the above code snippet, then all we have to do is wrap them in curly braces and prefix the block with the $ label syntax. This results in reactive statements . Any values within the reactive block become dependencies of the reactive statement. When any of these values change, the reactive statement gets re-run. This is perfect in case we want our word cloud to update anytime we provide a different set of words. Below, I'm going to show you how to build a word cloud with D3 and Svelte. The word cloud will display the frequency of words in the lyrics of of a song under the Billboard Hot 100 list, Vampire, by Olivia Rodrigo. The larger the word, and the less faded the word is, the greater the frequency of word in the lyrics. By the end of this tutorial, you will have built the following word cloud: To set up a new Svelte project with Vite and TypeScript , run the command npm init vite . Note : You may generate a new Svelte application with SvelteKit, but this tutorial is only focused on building out a single Svelte component for the word cloud. Therefore, it’s more preferred to use a lighter template so that you don’t need to mess around with extra project files. For the word cloud visualization, we will need to install two specific D3 modules: Run the following command to install these D3 modules and their type definitions in the Svelte project. First, delete the src/lib directory and src/app.css file. Then, in src/main.ts , omit the import './app.css' statement at the top of the file. In the src/App.svelte file, clear out the contents of the script, style and markup sections. Within the script section, let’s add the import statement for the <WordCloud /> component and a variable named lyrics that’s set to the lyrics of the song Vampire, like so: ( src/App.svelte ) Within the style section, let’s add some minor styles to horizontally center the <WordCloud /> component in the <main /> element. ( src/App.svelte ) Note : Styles defined in the <App /> component won’t leak into other Svelte components. Within the <main /> element of the markup section, call the <WordCloud /> component. Also, pass lyrics to the text prop of the <WordCloud /> component, like so: ( src/App.svelte ) Within the src directory, create a new folder named components . This folder will contain any reusable components used in this Svelte application. In this case, there will only be one component in this directory: WordCloud.svelte . Create this file inside of the src/components directory. Within the src/components/WordCloud.svelte file, begin with an empty script section for the <WordCloud /> component: ( src/components/WordCloud.svelte ) At the top of the script section, import d3Cloud from the d3-cloud module. d3Cloud instantiates a new cloud layout instance, and it comes with chainable methods for configuring: Additionally, import three methods from the d3-array module: ( src/components/WordCloud.svelte ) Then, declare the text prop that the <WordCloud /> component currently accepts. Set its default value to an empty string if no value is passed to the text prop. ( src/components/WordCloud.svelte ) d3Cloud comes with a chainable method called .words() . This method accepts the words and their frequencies as an array of objects with two properties: To turn the string of text into an array of objects with these properties, we’ll need to: Add these lines of code to the script section of the <WordCloud /> component, like so: ( src/components/WordCloud.svelte ) Like with any D3 data visualization, you need to define its dimensions. The dimensions consist of: In the <WordCloud /> component’s markup section, add an <svg /> element and set its width , height and viewBox using the values from dimensions . Since the words will be displayed using the Helvetica font family, let’s set font-family to “Helvetica.” Note : text-anchor="middle" aligns the middle of the text to the text’s position. This is important since the layout algorithm determines positions using the middle of the text as the reference. By default, the start of the text gets aligned to the text’s position. Next, define a wordPadding variable that specifies the numerical padding to apply to each word in the word cloud. Since d3-cloud internally uses an HTML5 <canvas /> element to simulate the layout algorithm, this padding (in pixels) gets multiplied by 2, and this product gets set to the lineWidth property of the canvas’s drawing context. For now, we’ll set wordPadding to 2. Add these lines of code to the script section of the <WordCloud /> component, like so: ( src/components/WordCloud.svelte ) With all of the necessary variables set, let’s call d3Cloud() and configure it using the following chainable methods: Anytime a word is successfully placed in the canvas that’s used to simulate the layout algorithm, push an object with the calculated font size ( size ), coordinates ( x and y ), rotation ( rotate ) and the word itself to an array named cloudWords . Once everything is set up, call the .start() method on cloud to run the layout algorithm. However, remember that Svelte’s reactivity only gets triggered on assignments. Since the .push() method mutates the array, we cannot use cloudWords to render the list of words in the markup section of the <WordCloud /> component. Therefore, once the layout algorithm finishes running, assign cloudWords to words . Then, within the <svg /> element in the markup section of the <WordCloud /> component, use an each block to loop over the list of words and render a list of <text /> elements inside of a <g /> element (for grouping the <text /> elements), like so: Add these lines of code to the script section of the <WordCloud /> component, like so: ( src/components/WordCloud.svelte ) When you run the project in development via npm run dev , you should see a word cloud that looks like the following: Currently, the size of a word communicates its frequency in a block of text. The larger the word, the more frequent the word appears in the block of text. However, what if we wanted to also communicate a word’s frequency based on the word’s opacity? For example, the more faded a word is in the word cloud, the less frequent it appears in the block of text. To do this, we’ll need to use the extent() method from the d3-array module to determine the maximum frequency. Then, by dividing a word’s frequency from the maximum frequency, we get decimal values that can be set to the word’s <text /> element’s opacity attribute, like so: Try customizing the word cloud for your own textual data. If you find yourself stuck at any point while working through this tutorial, then feel free to check out the live demo of this project in the following CodeSandbox: If you want to learn more about building visualizations with D3 and Svelte, then check out the Better Data Visualizations with Svelte course by Connor Rothschild, a partner and data visualization engineer at Moksha Data Studio.

Thumbnail Image of Tutorial Building a Word Cloud with D3 and Svelte

Learn SvelteKit by Building a Reddit Clone Application

SvelteKit is a serverless-first framework for building high-performance, web applications with Svelte. Newcomers to Svelte can think of SvelteKit as Next.js or Nuxt.js, but for Svelte. First announced in October 2020 , SvelteKit entered public beta in March 2021 and is the successor of Sapper , a now deprecated Svelte-based framework. With the Svelte team abandoning sveltejs/template and sveltejs/sapper-template , SvelteKit became the de-facto framework for building any type of web application (of any size) with Svelte. SvelteKit inherits many of Sapper's functionality and features: However, the Svelte team designed SvelteKit to address Sapper's shortcomings: Although the road to v1.0 remains in progress, you can still build production-grade, SEO-friendly applications with the SvelteKit beta. The best part of SvelteKit is the ability to build Next.js-like applications with an amazing developer experience and with Svelte, which exceeds React in terms of performance and size. Svelte's compiler turns Svelte components (written with an intuitive, declarative API) into efficient JavaScript. Below, I'm going to show you: By the end of this tutorial series, you will have built a full-functional Reddit clone application with SvelteKit and TailwindCSS: To get started, run the following command to create a new SvelteKit project: The npm create command is an alias for the npm init command. This command gets transformed to the command npm exec create-svelte@latest <project-name> , which remotely fetches the create-svelte CLI executable and runs it to create a new SvelteKit project. The CLI tool will present a series of prompts that determine how you want to set up the project: After the project has been created, change your current directory to the project's directory and install the dependencies. When you open the package.json file, you will notice SvelteKit already provides several npm scripts: Other npm scripts get added based on the additional tooling that you told the SvelteKit CLI to add to the project: To verify that the application runs properly, start up the development server and visit the application at http://localhost:5173 : Currently, there is not much on the page, but that will change as you progress further in this tutorial. Now that you know how to locally run a SvelteKit application, let's take a look at the remaining files and directories that make up a SvelteKit project. The following is the directory and file structure of a barebones SvelteKit project: Within the root of the project directory, you will find the following files: When you look inside the src directory, you find the following files and directories: The src directory can also have the following optional files and directories: The static directory contains all of the application's static assets, such as favicon.png (the SvelteKit project already comes with a default favicon.png file) and sitemap.xml . The tests directory contains any E2E tests that should be ran by Playwright. Continue on to the second part of this tutorial.

Thumbnail Image of Tutorial Learn SvelteKit by Building a Reddit Clone Application

How is Svelte different than React?

To get a better understanding of what Svelte brings us, it helps to step back and look at how we got here: Back in the 90s, in the original version of the web, there was only HTML. Browsers displayed static documents without any interactivity. The only way to get updated information, was by reloading the page, or navigating to a new page. In 1995, Netscape released JavaScript , making it possible to execute code on the end-user's machine. Now we could do things like: As developers began experimenting with this newfangled JavaScript thing, they found one aspect really tough: dealing with the differences between browsers. Both Netscape Navigator and Internet Explorer did things in their own way, making developers' responsible for handling those inconsistencies. The result was code like: This kind of browser detection code littered codebases everywhere. The extra branching was a nuisance, like a cognitive tax, making code harder to read and maintain. Translation: not fun. In 2006, John Resig released a compatibility layer called jQuery . It was a way to interact with the DOM without being an expert on browser feature matrices. It completely solved the inconsistency issue. No more if (isNetscape) or if (isIE) conditions! Instead, we could interact with the page using CSS selectors, and jQuery dealt with the browser on our behalf. It looked like this: But there were some challenges here too: In 2010, Google launched AngularJS 1.x , a framework that helps with state management. Instead of writing jQuery code, like: Expressions (called bindings) could be embedded directly inside the HTML: and Angular would sync those bindings for us. Later, if we change our HTML, say by switching an <h1> to an <h2> , nothing breaks with the Angular version. There's no CSS selectors to update. AngularJS components looked like this: The magic was that anytime you changed something on the $scope variable, Angular would go thru a "digestion cycle", that recursively updated all the bindings. But there were some problems here too: In 2013, Facebook launched React , a library for syncing state with UI. It solved some issues that AngularJS 1.x had. It's isomorphic, it can render HTML both on the server and in the browser, fixing the SEO problem. It also implemented a more efficient syncing algorithm called Virtual DOM . Refresher: Virtual DOM keeps a copy of the DOM in memory. It uses the copy to figure out what changes (the delta), while limiting potentially slow interactions with the browser DOM. (Though it's been pointed out that this may be overhead .) It's still conceptually similar to AngularJS, from a state management perspective. React's setState({value}) or in more recently, the useState() hook, is roughly equivalent to Angular's $scope.value = value . Hook example: React relies on developers to signal when things change. That means writing lots of Hook code. But Hooks aren't trivial to write, they come with a bunch of rules , and those rules introduce a extra cognitive load into our codebases . In 2019, Rich Harris released Svelte3. The idea behind Svelte is: What if a compiler could determine when state changes? That could save developers a lot of time. It turns out to be a really good idea . Being a compiler, Svelte can find all the places where our code changes state, and update the UI for us. Say we assign a variable inside a Svelte component: Svelte detects the let statement and starts tracking the variable. If we change it later, say year = 2021 , Svelte sees the assignment = as a state change and updates all the places in the UI that depend on that binding. Svelte is writing all the Hooks code for us! If you think about it, a big part of a developer's job is organizing state, moving state back and forth between the UI and the model. It takes effort, and it's tricky to get right. By offloading some of that work to compile-time tools, we can save a lot of time and energy . Another side effect is, we end up with less code . That makes our programs smaller, clearer to read, easier to maintain , cheaper to build, and most importantly: more fun to work with. P.S. This post is part of a new course called "Svelte for React Devs" So stay tuned!

State Management with Svelte - Stores (Part 3)

Disclaimer - If you are unfamiliar with the Context API in Svelte applications, then please read this blog post before proceeding on. You must understand the limitations of the Context API to better understand stores and how they address those limitations. For components in a Svelte application to share data irregardless of the subtree they belong to in the component hierarchy, Svelte provides stores for handling global state via the svelte/store module. Unlike the Context API, which involved setting contexts directly in the <script /> block of a component via setContext , stores can be created outside of a component in their own dedicated modules. Yet, like the Context API, a store can only contain a single value. This value can be a primitive, an object, an array, etc. When a component subscribes to a store, the component can receive the updated value from the store and re-render accordingly. Like props, stores are reactive . Stores are designed to cover practical use cases such as theming, accommodating internalization/localization (i18n), persisting a logged-in user's information, etc. Svelte supports four types of stores: A readable store is a store whose value cannot be set within a component subscribed to it. Components can only read from it and cannot write to it. To create a readable store, first import the readable function from the svelte/store module: Then, call the readable function. It accepts two arguments: The readable function returns an object containing a subscribe method, which allows a component to subscribe to the store and listen for changes to its value. The subscribe method accepts a single argument, a function that provides the store's value. Commonly, a component variable is set to this value so that it can be displayed or used for the component's internal state. This method returns an unsubscribe method, which allows the component to unsubscribe from the store. The unsubscribe method is called within the onDestroy lifecycle method to avoid memory leaks, which can result from the component being instantiated and being destroyed many times, leaving subscriptions of previous component instances still in memory. Example #1 : A component subscribes to a readable store with the value "Hello World!" It sets the message variable to this value, and this message is rendered within the <h1 /> element. The UI will display "Hello World!" in big, bold text. ( Component.svelte ) Example #2 : <ComponentA /> and <ComponentB /> both subscribe to a readable store imported from an external module, stores.js . Whichever component first subscribes to the store will trigger the function passed as a second argument to the readable method, which will print "Only called once!" to the developer tools console and replace the default value of "Hello World!" with "Lorem Ipsum." When the other component subscribes to the store, the function passed as a second argument to the readable method will not be triggered. When these components subscribe to the store, their message variable will be set to the store's value, now "Lorem Ipsum," and this message is rendered within the <h1 /> element. The UI will display two "Lorem Ipsum" in big, bold text. ( stores.js ) ( ComponentA.svelte / ComponentB.svelte ) ( Parent.svelte ) A writable store is a store whose value can be set within a component subscribed to it via pre-defined methods. Components can read from and write to it. To create a writable store, first import the writable function from the svelte/store module: Then, call the writable function. It accepts the same two arguments as the readable function mentioned above: an initial value of the store and a function that provides a set function for setting the value of the store. The writable function returns an object containing three methods: Example #1 : A component subscribes to a writable store with the value zero. It sets the count variable to this value, and this count is rendered within the <h1 /> element. Initially, the UI will display 0 in big, bold text. Along with this text, the UI will present two buttons, one for incrementing the count by one each time it is clicked and one for resetting the count back to zero. To increment the count by one, use the store's update method, which accepts a function that provides the current value of the store as an argument and returns the new value to be set to the store. When the "Increment" button is clicked, the count rendered within the <h1 /> element will be updated to the newly incremented value. To reset the count to zero, use the store's set method, which accepts the value to be set to the store. Pass it the value zero. When the "Reset" button is clicked, the count rendered within the <h1 /> element will be updated to zero. ( Component.svelte ) Example #2 : <ComponentA /> and <ComponentB /> both subscribe to a writable store imported from an external module, stores.js . Whichever component first subscribes to the store will trigger the function passed as a second argument to the writable method, which will print "Only called once!" to the developer tools console and replace the default value of zero with one-hundred. When the other component subscribes to the store, the function passed as a second argument to the writable method will not be triggered. When these components subscribe to the store, their count variable will be set to the store's value, now one-hundred, and this count is rendered within the <h1 /> element. The UI will display two "100" in big, bold text along with two sets of "Increment" and "Reset" buttons. When any of the "Increment" buttons is clicked, the two count values rendered will be incremented by one (store values are reactive, and both components are subscribed to the same store). When any of the "Reset" buttons is clicked, the two count values rendered will be changed to "0." ( stores.js ) ( ComponentA.svelte / ComponentB.svelte ) ( Parent.svelte ) A derived store is a store whose value is derived from values from at least one store. Because the derived value depends on other stores, its value cannot be set by a component. Components can only read from it and cannot write to it. To create a derived store, first import the derived function from the svelte/store module: Then, call the derived function. It accepts three arguments: Like the readable function, the derived function returns an object containing a subscribe method, which allows a component to subscribe to the store and listen for changes to its value. Example : A component subscribes to both a writable store, which contains an RGB value (an array of three numbers, each representing an individual channel of an RGB value), and a derived store, which contains an HSL value derived from this writable store's RGB value. Both are set with default values representing the color white in their respective formats: [255, 255, 255] and [0, 0, 1] . The inputs under the "RGB" section of the UI are each bound to a value in the rgb array, which is set to the value of the RGB store ( rgbStore ). The inputs under the "HSL" section of the UI are each bound to a value in the hsl array, which is set to the value of the HSL store ( hslStore ). When the user changes the value of any one of the three inputs (restricted to numbers within the range 0 to 255) under the "RGB" section of the UI, the values of the three inputs under the "HSL" section of the UI will be changed to the HSL value equivalent to this RGB value. Svelte Derived Store Demo - RGB-HSL Conversion ( utils.js ) ( stores.js ) ( Component.svelte ) Thus far, subscribing to a store in a component involves a lot of boilerplate code: This boilerplate code grows proportionally to the number of stores the component subscribes to. For a component that is instantiated and destroyed many times, it is important to unsubscribe the component from the stores it subscribes to. Otherwise, the component's subscriptions remain in memory long after it's been destroyed, which will cause a memory leak . Fortunately, Svelte provides a convenient shortcut for components to auto-subscribe to stores. By prefixing the imported store's name with $ , the component automatically subscribes to the store and unsubscribes from the store when it is destroyed. Plus, the component can reference the store's value in its template without having to assign it to an extra variable and receive updates to this value. Let's rewrite the component in the derived store example using auto-subscriptions: To try it out, visit the demo here . ( stores.js ) ( Component.svelte ) Wow! Talk about a much cleaner approach! No longer will you need to manually subscribe to each store and write all of the unsubscription-related code involving the onDestroy lifecycle method. Under-the-hood, auto-subscriptions automatically handles all of this logic. With auto-subscriptions, you can name the store after the value it contains rather than just naming it as a store. In the above example, notice how the previously named rgbStore is now named rgb . This way, when its value is referenced in a component's template via the $ prefix, the name will reflect the value itself ( $rgb ). Also, an input can bind directly to the writable store's value and update it whenever the user changes the input's value. For writable stores, assignments done directly to these $ -prefixed variables will call the store's set method using the value to be assigned. This will set the rgb store's value to [0, 0, 0] upon the component's instantiation. Changing the rgb store's value will cause the derived value in the hsl store to be set to [0, 0, 0] . To retrieve the value of a store once (non-reactive), use the svelte/store module's get function. This is useful for allowing components to access values from stores they are not subscribed to, but yet, may need to access once in a while. Under-the-hood, get subscribes the component to the store, reads its value, and then, unsubscribes the component from the store all in one method. Let's take the refactored derived store example that uses auto-subscriptions, and rewrite the component to only convert the RGB value entered into the inputs to its HSL equivalent when the user clicks on a "Convert" button: To try it out, visit the demo here . ( Component.svelte ) Here, changes to the RGB inputs no longer automatically update the HSL inputs. When the user changes the value of any of the inputs in the RGB section, they must now click the "Convert" button, which retrieves the HSL value from the hsl store. The get method allows components to access such store values only when necessary. A custom store is an object that provides, at the minimum, the same functionality as any one of the native stores (readable or writable), and that can also provide additional functionality geared more towards domain-specific logic. When this object contains a "properly implemented" subscribe method, the object fulfills the store contract . This allows the object to be treated as a store. Its value becomes reactive, and the store can be referenced with the $ auto-subscription prefix. A "properly implemented" subscribe method must accept a function as an argument. This function must provide the store's value as an argument. Upon subscribe being called or the store's value being updated, this function will be called immediately (and synchronously), providing the store's current value as its argument. Additionally, this function must either... Referring back to the the svelte/store module's readable and writable methods, these methods provide minimal store implementations that fulfill the store contract: When a custom store optionally provides a set method, which sets the store's value and calls all of the store's active subscription functions, the store becomes a writable store. Let's take the refactored derived store example that uses auto-subscriptions, and modify the rgb store to provide additional methods for resetting the store's value to something pre-defined. In this case, setting the store's RGB value to red's, blue's, green's, black's or white's RGB value. To try it out, visit the demo here . ( stores.js ) If the custom store relies on readable or writable , then destructure out the methods they return ( subscribe , and for writable specifically, set and update ) and return them in the object representing the custom store. Group all of this code within an IIFE ( Immediately Invoked Function Expression ), which will contain all of the custom store's implementation details while not interfering with other custom stores that rely on readable or writable . The rgb custom store, previously a pure writable store, now provides five additional methods ( resetToBlack , resetToWhite , resetToRed , resetToGreen and resetToBlue ), each one setting this store's value to a pre-defined RGB value. ( Component.svelte ) Components can auto-subscribe to custom stores in the same way they can to pure readable, writable and derived stores. To access any of the custom store's methods, simply reference it via its corresponding property in its object representation. For example, rgb.resetToBlack references the resetToBlack method of the rgb store. If the user clicks on any one of the five buttons, then the value of the inputs under the RGB section will be changed to a pre-defined RGB value, and the inputs under the HSL section will also be changed due to them binding to a value of a derived store ( hsl ) that depends on the rgb custom store. Often, custom stores are useful for augmenting the capabilities of writable stores, such as validating a value prior to setting it as the store's value. Major e-commerce websites, such as Amazon, feature shopping cart buttons in their navigation bars. For a user to add a product to their shopping cart, they must first visit the product's detail page and press a button to add this product to their shopping cart. The shopping cart will be updated with the product. At any time, the user can remove the product from their shopping cart. Because components representing a product page and a navigation bar are likely to not have an ancestor-descendant relationship in a component hierarchy, to communicate with each other, they will both need to connect to a single store containing cart-related data. Svelte Store Demo - E-Commerce Shopping Cart ( App.svelte ) The demo displays a hypothetical e-commerce webpage. The <Header /> component serves as the navigation bar for this webpage, and it contains the shopping cart button. The <Products /> component shows all of the available products for the user to add to their cart and purchase later. ( stores.js ) This demo application involves four stores: ( Header.svelte ) The <Header /> component serves as a navigation bar. Here, it has a "Log In" link and a shopping cart button. ( Cart.svelte ) When the shopping cart button is clicked, a dropdown will appear. When the user adds a product to their cart, this dropdown will display this product, the sub-total of the entire cart, the amount to discount from the sub-total, an input for applying a coupon and a total (calculated as the difference of the sub-total and the discount). In this component, the auto-subscription $ prefix is used to directly access the cartStore 's and costStore 's values in the template code for rendering the cart's products, discounts and costs. Additionally, auto-subscriptions automatically handle store subscriptions and unsubscriptions. When a coupon is applied, it is checked against the list of valid coupons in $validCouponStore . If the coupon is found and recognized as a valid coupon, then it is added to the cartStore , which will then cause costStore to update the discount amount and total. A valid coupon can only be applied once. ( Products.svelte ) This component displays the products in the productStore . Notice how manually subscribing/unsubscribing to a store adds more boilerplate code to the <script /> block. When the user presses the "Add to Cart" button of a product, this will add the product to the cartStore via its addItem custom method. Svelte's built-in support for state management covers many common use cases, such as implementing site-wide theming, translating content for multiple locales (i18n) and handling the authenticated user's information. Recent versions of other front-end libraries, like Vue.js and React.js, have introduced their own built-in state management solutions. In Vue 2, provide / inject bindings are not reactive , which is similar to Svelte's Context API . In Vue 3, provide / inject can be used with the Composition API to add reactivity between provided and injected values via the ref / reactive method. Alternatively, a store pattern using the reactive method can be adopted for managing state. In pre-React v16, React offered an experimental Context API , and their documentation discouraged updating the context due to intermediate parent components possibly returning false in their shouldComponentUpdate lifecycle methods. In React v16+, React introduced an official Context API that is considered to be more efficient. Both of these versions of React's Context API are reactive. Using Vue 3's provide / inject Composition API and React v16+'s Context API, the data must come from a parent component and can only be shared with components within its subtree. In Vue 3, the parent component calls the provide method within its setup option to allow its child components to access those values when they call the inject method within their setup options. In React v16+, it is very common to see entire applications wrapped within global provider components so that the application state can be accessed by any component within the application's component hierarchy. With Svelte's stores, you don't have to wrap any components with a higher-order provider component or tie global state to a component. Just define a store within an external module and import it directly into any component whenever it is needed, irregardless of wherever the component is within the component hierarchy. Of course, there are third-party libraries such as a Redux that can also fulfill an application's state management requirements. Redux is a state management library for centralizing state in a single, immutable store (outside of components) and manipulating the state in this store predictably by dispatching pre-defined actions, which are each mapped to a different shape of the state in the store (based on the outcome of the manipulations). Over the recent years, criticism of Redux has grown as front-end libraries/frameworks implemented their own state management solutions. Often, the main complaint of Redux has been the " bloat " it adds to an application's production bundle. However, most developers seem to integrate Redux into their applications when they really don't need it. For the additional kBs Redux adds to a production bundle and the extra memory it consumes, Redux provides: If you don't need all of the boilerplate code and features that come with Redux, then you probably don't need Redux and can manage an application's state with the front-end technology's built-in state management solution. Remember to always evaluate the trade-offs! Try rewriting your Vue - Vuex or React - Redux (or Context API) projects with Svelte. You will likely be surprised at and appreciate the simplicity, flexibility and robustness of Svelte stores. If you want to learn more about Svelte, then check out Fullstack Svelte :

Thumbnail Image of Tutorial State Management with Svelte - Stores (Part 3)

State Management with Svelte - Context API (Part 2)

Disclaimer - If you are unfamiliar with props in Svelte applications, then please read this blog post before proceeding on. You must understand the limitations of props to better understand the Context API and how it addresses those limitations. For components that need to share data to lower-level descendant components (and slotted content) within the same subtree, the Context API offers two methods for these components to communicate data without prop drilling or dispatching events: getContext and setContext . When a component calls setContext , the component defines a context , which is a value (primitive or object) representing data that can only be accessed by the component's descendants via the getContext method. Defining a context with setContext requires the component to supply a context key and a value . The context key helps to retrieve the context value from the closest ancestor component with a defined context corresponding to this key. For a descendant component to consume context defined within one of its ancestors, call the getContext method, passing to it the context key. Note : The context key does not have to be a string; it can be any value. Using a string as the context key has the downside of conflicting with other contexts with the same context key, especially if these contexts belong to third-party libraries that you have little to no control over. Using an object literal as the context key ensures that its context won't conflict with other contexts since object literals are compared via referential equality. Both setContext and getContext must be called during component initialization at the top-level of <script /> , similar to lifecycle methods. Let's revisit the <Grandparent /> , <Parent /> and <Child /> components' example and refactor the code by substituting the props with context. ( Grandparent.svelte ) ( Parent.svelte ) ( Child.svelte ) This approach is much cleaner compared to the props approach. The intermediate <Parent /> component no longer contains any reference to message , which it previously received from the <Grandparent /> component and forwarded it directly to the <Child /> component. Only the descendant components concerned with message (in this case, the <Child /> component) receive it. At a minimum, a simple scatterplot consists of two labeled axes (an x-axis and y-axis) and some dots. Optionally, a scatterplot may display a legend mapping a dot's color to a specific category it belongs to (for classification purposes). If you break down a <Scatterplot /> component into its constituent components, then you might arrive at this component hierarchy: Note : <svg /> is commonly the root element of interactive data visualizations, especially those built using D3 . When you include props, then you may notice how reliant these components are on the same set of props. As the requirements of the visualization grow and more features are added, passing these props explicitly to each of these components becomes repetitive and unmaintainable. Visit this simple Svelte REPL demo to see how the Context API allows these child components to receive all of this data from a single, common parent component ( <Scatterplot /> ): Context API Demo - D3 Scatterplot The scatterplot shows the relationship between the petal length and petal width of flowers classified as species of Iris (Iris setosa, Iris virginica and Iris versicolor). If you have a background in a data science, statistics or machine learning background, then you are likely to have encountered and explored this multivariate dataset when learning introductory classification algorithms. ( App.svelte ) The <App /> component fetches the Iris dataset from a GitHub Gist, and it establishes the petal length as the independent variable ( x ) and petal width as the dependent variable ( y ) to be plotted in the scatterplot. Each data point is categorized as one of three flower species: setosa, versicolor and virginica. Once the data is fetched, the <Scatterplot /> component is rendered using this data and custom configuration options. Note : The <Scatterplot /> component can accept data from either a remote source (as shown above via d3.csv , fetch , etc.) or locally with this arrangement. The other props passed to the <Scatterplot /> component configure certain aspects of the scatterplot such as its dimensions and axes. ( context-keys.js ) To avoid any conflicts with other contexts, the context key for the scatterplot will be a literal object. This object will be referenced by all of the scatterplot's constituent components when they access the context set by the <Scatterplot /> component. ( Scatterplot.svelte ) The <Scatterplot /> component receives a set of props from a consuming component (in this case, <App /> ), and creates a context via setContext , which contains these values. Notice how no props are passed to the <Dots /> , <XAxis /> , <YAxis /> and <Legend /> components because each of these components will access those values directly from this context via getContext . ( Dots.svelte ) Since both axes are drawn dimensions.margins.left pixels away from the left-side of the visualization, we must automatically translate all of the dots horizontally by this same amount of pixels to ensure that they are drawn within the confines of these axes ( translate(${dimensions.margins.left}, 0) ). Then, each data point is drawn as a dot with a radius of three pixels, colored based on its flower species and positioned based on the values of xScale(item.x) and yScale(item.y) . ( XAxis.svelte ) ( YAxis.svelte ) To generate an axis' tick marks, call the ticks method on the scale function ( xScale or yScale ). The number of tick marks created is based on the number passed to the ticks method. To space the tick marks out evenly, translate each tick mark by a number of pixels determined by scale(tick) ( translate(${xScale(tick)} 0) for each x-axis tick mark and translate(0, ${yScale(tick)}) for each y-axis' tick mark). To position the labels ( <text /> element, last child of the outermost <g /> element), space them slightly away from the halfway point of its corresponding axis line ( <path class="axis-line" /> element). ( Legend.svelte ) The legend is placed 25 pixels to the right of the y-axis (adding x pixels to dimensions.margins.left for the horizontal translation ensures the legend is shifted x pixels from the y-axis) and 25 pixels from the top-side of the canvas. Each category is displayed with its unique color representation and label. If you have built React applications, then up to this point, Svelte's Context API may appear similar to React's Context API : sharing values between components of the same subtree without having to explicitly specify props at every level of the component hierarchy . In Svelte, the setContext creates the context, sets its value and automatically provides access to this context for all of the component's descendants. In React, you must first create the context with the createContext method. Note : According to React's documentation , providing a default value to createContext is useful for testing components in isolation without having to wrap them within a provider component. This value serves as a fallback for when a component has no matching provider (for example, <ScatterplotCtx.Provider /> ) above it. For components to access this context value, create a provider component and have it wrap all of these components: In React, updates to the provider component will cause the useContext hook to trigger a rerender using the latest context value passed to this provider component. However, in Svelte, descendant components cannot receive updates from a context whenever its set to a different value via a subsequent call to setContext . These components are only able to access the values made available to them from their ancestor component (the one setting the context) during component initialization. Since the components are not updated with the new context value and not re-rendered as a result of those changes, we cannot consider the Context API as reactive feature of Svelte. For reactivity, we must use props and/or stores , which allow components to access data and subscribe to updates from global data stores (not restricted to a subtree of components). Proceed to the next blog post to learn more about Svelte stores. If you want to learn more about Svelte, then check out Fullstack Svelte :

Thumbnail Image of Tutorial State Management with Svelte - Context API (Part 2)

State Management with Svelte - Props (Part 1)

Each component of a client-side application contains internal state that encapsulates its own data, which determines the component's behavior and stores business-related data for rendering. When composing many components into a multi-level hierarchy, components must communicate data and coordinate amongst each other to perform more complex tasks. For example, a <SearchBar /> component might pass a list of search results to a <TypeaheadDropdown /> component to display suggestions based on the currently typed query. There are three common approaches to facilitate communication amongst the various components within a Svelte application: Having full control over state within an application allows developers to know how data flows throughout the application, better reason about the data and optimize accordingly. Modeling data flow with props, contexts and/or stores improves the organization of state, normalizes data to reduce instances of duplicated data and curtails the amount of time spent on debugging (quickly identify the component/s or portions of state responsible for a bug). Below, and in two additional blog posts, I'm going to show you: The simplest form of communication involves a parent component passing data to its direct child component/s via props . This concept is widely adopted in other popular component-based libraries/frameworks, such as React and Vue . In Svelte, the export keyword defines a prop that a component can accept from its consumers. ( Parent.svelte ) ( Child.svelte ) With props, data flows unidirectionally downwards from a higher-level component to a lower-level component in the component hierarchy. This means changes made to a prop in a child component will not propagate back to its parent component and yield any unwanted side effects. Unlike two-way data-binding in AngularJS , which caused performance issues and modal updates to cascade, one-way data binding with props reduces the number of possible points of failure due to the predictable nature of component/application state. If multiple props need to passed to a component, then consider packing all the props into an object and spreading them onto the component, which serves as a convenient shortcut for passing many props rather than individually specifying them. ( Parent.svelte ) ( Child.svelte ) If the parent component does not specify the prop on the child component, then its value will be set to undefined by default. However, instead of setting its value to undefined , the prop can be set to a default initial value. ( Parent.svelte ) ( Child.svelte ) Specifying props in a component with export let allows those props to be modified within the component itself. ( Parent.svelte ) ( Child.svelte ) When clicking the button and incrementing the value of the prop count , the newly incremented value is logged to the developers tool console, which indicates this prop being modified in the <Child /> component. However, this change is not propagated to the <Parent /> component. The count displayed within its <p /> tag remains zero no matter how many times you click on the "Increment" button. Try it out here . Swapping let for const changes the behavior of export . Unlike variables declared with export let , variables declared with export const , export function or export class are not props, but instead, are readonly constants that can be imported into other components as named imports. ( Parent.svelte ) ( Child.svelte ) Try it out here . To export these variables for consumption in other components via an import statement, declare the <script /> block with the attribute context="module" , which will execute the code within the <script /> block once upon the evaluation of the module, not the instantiation of the component. Uncommenting out any of the count++ statements and then clicking on the button bound to the event handler containing this statement will result in an error being logged to the developers tool console and count not being incremented. Variables declared with export const cannot be reassigned to a different value. This also applies to variables declared with export function and export class . Note : Properties of an object declared with export const can be modified, but the reference to the object cannot be changed. Suppose you decide to export a function that changes a value within the component it is exported from. ( Parent.svelte ) ( Child.svelte ) Clicking the "Increment" button will call the imported incrementCount function. When incrementCount is executed, the value of count is incremented. Because count is declared within a <script context="module" /> block, count is not reactive, and therefore, the count value displayed within the <p /> tag remains zero. A function can be exported from an instance directly and accessed as a property on the component's reference, which can be obtained via the bind:this directive. These properties are accessible after the component has been mounted to the DOM. ( Parent.svelte ) ( Child.svelte ) When clicking the "Increment" button, not only is count incremented, but its new value is displayed in the <p /> . For grandchild components to receive data from grandparent components, that data must first be passed from the grandparent component to its child component (the grandchild's parent component), and then, that data must be passed from this parent component to its child component (the grandchild component). ( Grandparent.svelte ) ( Parent.svelte ) ( Child.svelte ) This process of explicitly and redundantly passing data from higher-level ancestor components to lower-level descendant components via props is known as prop drilling . As the number of component layers increases, it becomes more difficult to track these props, especially when refactoring components and having to manually rename or remove props. In the above example, if we decide to rename the message prop to greeting , then we would have to start renaming the prop at the <Grandparent /> component and traverse down its subtree, renaming the prop at each subsequent component (the <Parent /> and <Child /> components). Also, the intermediate <Parent /> component does not make use of the message prop whatsoever. It simply receives this prop and passes it directly to the <Child /> component. Having these types of props in our components can add unnecessary clutter to them and exacerbate our ability to understand and maintain these components. Alternatively, to make data available to a component and its descendants without prop drilling, Svelte provides the Context API . Proceed to the next blog post to learn more about Svelte's Context API. If you want to learn more about Svelte, then check out Fullstack Svelte :

Thumbnail Image of Tutorial State Management with Svelte - Props (Part 1)

Svelte Lifecycle Method - beforeUpdate

In Svelte, a component's beforeUpdate lifecycle method is called before the component is updated as a result of a state change. When the component receives new prop values or has its local state modified, the component's beforeUpdate lifecycle method is called before any updates to the DOM are made. Once the beforeUpdate lifecycle method finishes executing, the DOM will be updated with these data changes, which will allow the subsequent call to afterUpdate to have access to a completely synced DOM. Being able to schedule a callback to run at this phase of a component's lifecycle ensures that the value of certain DOM properties, such as a container element's scrollTop , can be cached prior to being updated. Then, these cached values can be used to revert those properties back to what they were originally. Here's a template of how the beforeUpdate lifecycle method is used inside of a component: Note : beforeUpdate is called before the component's initial onMount . Below, I'm going to show you: Suppose you are formatting text within an editable element, such as an <input /> or <textarea /> via a set of controls in a floating tooltip. When you create a selection by dragging your cursor over a subset of the text and click on any one of the tooltip options to transform the text, the selected text should be modified with the selection and focus on the editable element still intact. By default, clicking anywhere outside of an editable element will cause it to lose its focus and current text selection. This does not happen when clicking on any of the buttons in the tooltip because of additional code that preserves the selection and focus. Visit this simple Svelte REPL demo to see how both the focus and text selection can be immediately restored using the beforeUpdate lifecycle method: Demo - beforeUpdate Lifecycle Method - Restore Input Cursor Position In this demo, there are four buttons, each of which transform the input field's text selection differently: When any one of these buttons is clicked while there is a text selection in the input field, the transformText function is called. This function transforms the text selection and sets value to the newly transformed text. Because value is updated with a new value, the beforeUpdate lifecycle method will be called, which checks if input exists (since beforeUpdate is called before the component is mounted) and caches the start and end positions of the text selection. After the DOM is updated and the new value is rendered within the input field, the afterUpdate lifecycle method will be called, which will recreate the text selection based on the cached positions and place the focus back on the input field. If you have built React applications, then you will have probably noticed how beforeUpdate can be used similarly to getDerivedStateFromProps / shouldComponentUpdate / getSnapshotBeforeUpdate . Try rewriting some of the those components that use getDerivedStateFromProps / shouldComponentUpdate / getSnapshotBeforeUpdate as Svelte components that use beforeUpdate . Because beforeUpdate is often used in tandem with afterUpdate , check out the afterUpdate blog post for more examples using beforeUpdate . If you want to learn more about Svelte, then check out Fullstack Svelte :

Thumbnail Image of Tutorial Svelte Lifecycle Method - beforeUpdate

Svelte Lifecycle Method - onMount

In Svelte, a component's onMount lifecycle method is called after the first time the component has been rendered to the DOM. For example, if you have a component that is wrapped within an {# if} block, then when this block's conditional statement is fulfilled, the component will be mounted to the DOM, at which point onMount will be called. Being able to schedule a callback to run at this phase of a component's lifecycle ensures that DOM elements within the component will be available for your code to access/manipulate. Here's a template of how the onMount lifecycle method is used inside of a component: Considered the most commonly used lifecycle method, onMount covers a wide diversity of use cases such as... Below, I'm going to show you: When you visit the G-Mail login page, you will notice that the e-mail address input field is automatically focused: This convenience automates away the initial click (or tabbing) into the input field that the user would have to do before being able to type in their e-mail address. Using the onMount lifecycle method, the focus can be moved to an input field when the component is initially rendered. Visit this simple Svelte REPL demo to see how to automatically focus an input field using the onMount lifecycle method: Demo - onMount Lifecycle Method - Login Form When you load the Svelte REPL, the e-mail address input field is automatically focused (indicated by its blue outline). The bind:this directive sets the variable it's passed a reference to an element's DOM node. Here, the emailAddressInput variable is set to the <input type="email" /> element. Since onMount runs after the component has been rendered, the input field will exist by the time this method is executed. Therefore, emailAddressInput will have been set to this input field, and the focus can immediately be moved to it. Note : Automatically focusing into an input field may skip over vital information a user using assistive technologies should be aware of. This may have negative implications on the accessibility of the application. Lazy-loading content reduces the initial load time of an application and reduces bandwidth by delivering only what the client has requested. Imagine having to wait seconds or minutes for a large webpage containing tables with thousands or millions of rows to be downloaded before seeing any content in your browser. Before the webpage finishes downloading, you would have most likely moved on to a different webpage. Wouldn't it be better if you were presented some content immediately (to keep you engaged), and then be shown a "loading" message when you request to view a large table? The onMount lifecycle method can be used to retrieve data from a remote API. This data can then be set to a variable in your component, which will cause the component to only re-render the part of the DOM that's affected by changes to this variable. This is especially useful for lazy-loading a table that contains many records. Visit this simple Svelte REPL demo to see how to fetch motor vehicle collisions data from the NYC Open Data API and render this data as rows of cells in a table using the onMount lifecycle method: Demo - onMount Lifecycle Method - NYC Open Data API Here, we are fetching data from the NYC Open Data Portal, particularly on NYC motor vehicle collisions . Each record of this dataset features the location of the accident, the vehicles involved, the number of fatalities, etc. For fetching data, we are using the native fetch method. The fetch method returns a Promise , so we will schedule an async callback to run when the component is mounted. While the data is being fetched, a "Loading..." message is presented to the user to notify them of the table's status (initially, isLoading is set to true , and this flag toggles this message on/off). Once the data is downloaded and parsed, the collisions variable is set to this data and the isLoading flag is set to false. As a result, the "Loading..." message disappears, and a select number of features of each record are displayed in the table. Note : Alternatively, this can be accomplished with an {#await } block ! Note : Since onMount is not ran during server-side rendering, if you need to fetch data within a component after its initial rendering, then it must be done within onMount and not outside at the top-level of <script /> . Note : Since async functions always return a Promise , onMount cannot return an unmount function since it must synchronously return a value. Event listeners execute code when an event, such as moving the mouse, takes place on the element it's binded to. In component-based applications, event listeners are registered once the component has been rendered to the page. Visit this simple Svelte REPL demo to see how to add an event listener on the window "resize" event using the onMount lifecycle method: Demo - onMount Lifecycle Method - Window Resize As you resize the browser window, notice how the window width displayed in the view changes. Just before the component is unmounted from the DOM, the unmount callback returned from onMount will be executed. This will remove this event listener from window , which will avoid memory leaks in legacy browsers, such as Internet Explorer, that do not automatically garbage-collect event handlers of removed DOM elements. When embedding a widget/plugin from a third-party library, those libraries will need to know where to place the widget/plugin in your application. For example, to display Google Maps via Google's Maps JavaScript API , the first argument to the google.maps.Map method is a reference to an existing DOM element (often document.getElementById('map') ) on the page where you wish to place the map. Visit this simple Svelte REPL demo to see how to embed a Leaflet map into your Svelte application using the onMount lifecycle method: Demo - onMount Lifecycle Method - Leaflet Map The <svelte:head /> element inserts elements into the <head /> element of the document. In this context, we are adding the Leaflet CSS and JavaScript files. By using <svelte:head /> , it keeps all Leaflet-related code encapsulated within a single component that contains all code related to rendering the Leaflet map. When the component is mounted, the <div id="map" /> container element will exist when the onMount callback is executed. The Leaflet library will be able to find this element and initialize the map. Note : This can also be done with Google Maps, but this example uses Leaflet since the Google Maps API requires an API key. To generate this API key, you must provide Google with your billing information in their Google Cloud Platform, and I felt this would add more an unnecessary obstacle to learning how load an embeddable widget/plugin with onMount . Note : If the Leaflet map is toggled on/off, then return an unmount callback that runs map.remove() to destroy the map and clear all of its related event listeners. Let's take the focus input example and refactor it. Instead of having the onMount code (and its contents) in the same file as the component, let's move it into an external module. Demo - onMount - External Module ( onMount.js ) ( App.svelte ) Notice how the bind:this directive was removed from the e-mail address input field. This is because the reference of the DOM node captured by this directive cannot be passed as an argument to the onMountFocusInput method. The DOM node reference will not be available when this method is executed since it is called at the top-level of the <script /> tag. Instead, we can pass an id value so that onMount can query for the input field element once the component that contains it is rendered. Additionally, by moving this onMount code outside of the component, it can be reused for other components that may need to automatically focus an input field when they are rendered to the page. If you have built React applications, then you will have probably noticed how similar onMount is to componentDidMount / useEffect . Try rewriting some of the those components that use componentDidMount / useEffect as Svelte components that use onMount . If you want to learn more about Svelte, then check out Fullstack Svelte :

Thumbnail Image of Tutorial Svelte Lifecycle Method - onMount

Svelte Lifecycle Method - onDestroy

In Svelte, a component's onDestroy lifecycle method is called before the component is removed from the DOM. For example, if you have a component that is wrapped within an {#if} block and it is currently rendered to the DOM, then when this block's conditional statement evaluates to false , the component will be unmounted from the DOM, at which point onDestroy will be called. Being able to schedule a callback to run at this phase of a component's lifecycle ensures that cleanup-related operations can be ran and previous application states can be resumed. Here's a template of how the onDestroy lifecycle method is used inside of a component: Compared to the function returned from onMount , there are specific reasons for using onDestroy : As a vital lifecycle method, onDestroy covers a wide diversity of use cases such as... Below, I'm going to show you: When a modal dialog is closed, the focus should return back to the element that opened the modal dialog. Not doing so would hurt the experience of users who rely on keyboards and/or assistive technologies to navigate through webpages. To rescue the focus: Visit this simple Svelte REPL demo to see how to refocus a previous element using the onDestroy lifecycle method: Demo - onDestroy Lifecycle Method - Modal ( Modal.svelte ) When the "Open Modal" button is clicked, it sets the isModalOpened flag to true , which causes the <Modal /> component to be rendered to the page. When an instance of the <Modal /> component is created, its <script /> block is executed, and previouslyFocused is set to document.activeElement , which references the most-recently focused element (the "Open Modal" button). Notice that the "Close Modal" button in the modal dialog is focused due to its autofocus attribute. When you click the "Tab" key, the focus is trapped within the modal dialog (each press moves the focus to each link, followed by the "Close Modal" button, and back, repeating in a cycle), which prevents the focus from escaping the modal dialog. When you press the "ESC" key or click the "Close Modal" button, then the "close" event is dispatched, which will execute the closeModal function, set the isModalOpened flag to false and remove the modal dialog from the DOM. Before the modal dialog is unmounted, the callback passed to onDestroy will be ran. The focus will resume back to the previously focused element, the "Open Modal" button. Note : In Firefox and Safari, document.activeElement references the <body /> element in an <iframe /> element (where the Svelte REPL displays the result of the Svelte code). In the demo, a reference to the "Open Modal" button is passed to the <Modal /> component as a prop, and it is manually used as the previously focused element if document.activeElement references the <body /> element. Removing event listeners is necessary for avoiding memory leaks in older browsers that don't automatically garbage-collect event handlers of removed DOM elements. A common pattern for registering and unregistering event listeners in Svelte is to perform these actions during the onMount and onDestroy lifecycle methods respectively. Visit this simple Svelte REPL demo to see how to remove event listeners in your Svelte application using the onDestroy lifecycle method: Demo - onDestroy Lifecycle Method - Removing Event Listeners (Window Resize) ( WindowResize.svelte ) Resizing the window updates the printed width value. By debouncing the event handler, the resize event listener will only call the event handler after the resize event has stopped firing for 300ms. Limiting the rate at which the event handler is executed will yield performance gains, especially in much larger applications. To trigger the onDestroy lifecycle method, press the "Toggle" button to toggle off the <WindowResize /> component. This will remove the registered resize event listener on the window object. If, instead, the event listener was binded to an element within the component, then the event listener can be binded to the element in onMount since the element will have been rendered by the time onMount is called. Likewise, the event listener can be removed from the element in onDestroy since onDestroy occurs just before the element is removed from the DOM, which means the element still exists when removing this event listener. To understand how a UI change can affect a user's engagement with your application, you might collect a set of metrics, such as bounce rate and average session duration, via Google Analytics or software custom-built to log this information. A simple metric to integrate into your application is tracking how long a user stays on a page. A rudimentary implementation of this would involve starting a timer the moment the user visits the page, and then stopping the timer the moment they exit the page. Visit this simple Svelte REPL demo to see how to log user activity in your Svelte application using the onDestroy lifecycle method: onDestroy Lifecycle Method - Logging User Activity ( RedditArticle.svelte ) In this example, each tab represents a "subreddit," a topic-specific, online community on Reddit ( r/science , r/technology and r/worldnews ). Clicking on any of these tabs will display a list containing the most popular articles for the corresponding subreddit. The <RedditArticles /> component is mounted anytime the user clicks on any of the subreddit tabs. Upon switching from one subreddit to another, the current <RedditArticles /> component will be unmounted, and a new <RedditArticles /> component will be mounted. The subreddit prop is passed to ensure the articles for the currently selected subreddit are loaded. When an instance of the <RedditArticles /> component is created, this represents the user landing on a new "page," and a timer begins to mark this ( let startTime = performance.now(); ). Once the user leaves the "page" (switching to a new subreddit), the onDestroy lifecycle method is called, and the difference between the time at which the component is unmounted and the recorded start time is calculated. This difference represents how long the user was on this subreddit before leaving. After performing this calculating, the difference can be sent to an API endpoint to be stored. All of the data collected can then be aggregated and viewed inside of a dashboard. Typically, in component-based architectures, data flows downwards from parents to children (unidirectional). In Svelte, stores allow data to be shared between components, regardless of their relationship in the component hierarchy. A store contains a subscribe method that notifies components of changes to the store's value. When the subscribe method is executed, an unsubcribe method is returned, which cancels a component's subscription to a store when called. Visit this simple Svelte REPL demo to see how to unsubscribe from a Svelte store subscription using the onDestroy lifecycle method: onDestroy Lifecycle Method - Scheduling Store Unsubscriptions ( RedditArticles.svelte ) In this example, the "Logging User Activity" demo has been repurposed with the <Subreddits /> component (the tabs) and the <RedditArticles /> component (the list of subreddit articles) both subscribed to a store named reddit . ( store.js ) currentSubreddit represents the currently selected subreddit (by default, it is r/science). Because the value of currentSubreddit can be modified, this store is a writable store, which means two additional methods are provided alongside the subscribe method: set (sets a new value for the store and synchronously executes every active subcription method of the store) and update (updates a value based on the current value in the store). For convenience, a custom method, setCurrentSubreddit , is made available, and it directly updates the currentSubreddit value. All components subscribed to the store will see the changes. In this case, both the <App /> and <RedditArticles /> components are subscribed to the store for changes to currentSubreddit . Imagine a scenario in which a component is mounted/unmounted many times throughout the lifetime of the application. If unsubscribe is not called upon unmounting the component, then its corresponding subscription will still be alive and will be executed upon future updates to the store even when the component the subscription is tied to has been unmounted. Try this out by commenting out the unsubscribe function call in the <RedditArticles /> component's onDestroy and adding a console.log() statement inside of the subscription function. As you switch tabs from one subreddit to another, watch as more and more messages are printed inside of the console. With so many subscriptions still in memory and not garbage-collected, eventually, this will cause a memory leak. To avoid this situation, the unsubscribe method must be called inside of onDestroy lifecycle method. Note : Subscribing to the store and adding a call to the unsubscribe method inside of many components that rely on the store can become tedious and resemble repetitive boilerplate code. Instead, just import the store and prefix a store value with a $ to auto-subscribe to it. The auto-subscription shorthand will allow components to auto-subscribe to the store and automatically unsubscribe from it when the component is destroyed. Check out the <Subreddits /> component for an auto-subscription example. ( Subreddits.svelte ) For third-party libraries such as Leaflet.js that embed interactive maps into an application, the provide methods for "cleaning-up" when they are removed from the DOM. For example, in the case of Leaflet.js, the remove method destroys the map and its layers and clears all of their corresponding event listeners. Visit this simple Svelte REPL demo to see how to clean-up an embedded Leaflet map in your Svelte application using the onDestroy lifecycle method: onDestroy Lifecycle Method - Clean-Up External/Third-Party Libraries ( LeafletMap.svelte ) When the map is toggled on, the <LeafletMap /> component's onMount lifecycle method is called and initializes a new map on a specified container element. Additionally, a marker icon is displayed, and an event listener is added to this icon. Whenever the icon is clicked, a popup opens above it. Once the map is toggled off, the <LeafletMap /> component's onDestroy lifecycle method is called and destroys the map and the marker and clears all of their corresponding event listeners such as zooming in the map, the opening of the marker icon's popup on clicking, etc. When server-side rendering a Svelte application, only one lifecycle method is called: onDestroy . Particularly, onDestroy is called after the application is rendered. For example, when building the static version of a Sapper application via npm run export , only onDestroy is called. To verify this, simply add a console.log statement into each lifecycle method call and observe the outputted logs in the CLI. ( src/routes/index.svelte ) If you have built React applications, then you will have probably noticed how similar onDestroy is to componentWillUnmount . Try rewriting some of those components that use componentWillUnmount as Svelte components that use onDestroy . If you want to learn more about Svelte, then check out Fullstack Svelte :

Thumbnail Image of Tutorial Svelte Lifecycle Method - onDestroy

Svelte Lifecycle Method - afterUpdate

In Svelte, a component's afterUpdate lifecycle method is called after the component is updated as a result of a state change. When the value of any of a component's props and variables changes, the component's beforeUpdate lifecycle method is executed prior to any DOM updates being made in response to these changes. Once the beforeUpdate lifecycle method is finished running, the DOM is updated to reflect the data changes. After completing this update, the afterUpdate lifecycle method is executed. Being able to schedule a callback to run at this phase of a component's lifecycle ensures that the DOM is completely updated and synced with any new state and prop values. Here's a template of how the afterUpdate lifecycle method is used inside of a component: When using the afterUpdate lifecycle method, remember that it runs on every state and prop change. For components that experience many state and prop changes, it can be quite cumbersome to track which variables/props have changed in order to then execute the appropriate code. This is unlike React's componentDidUpdate lifecycle method , which provides the previous props and state as arguments. Below, I'm going to show you: The Markdown syntax formats plain text into structured content that can be published to the web as valid HTML markup. Commonly, developers write API documentation and blog posts using Markdown. To avoid typos and inconsistencies while writing Markdown, tools and editors have been built to instantly live preview the rendered output of Markdown content. Visit this simple Svelte REPL demo to see how to live preview Markdown using the markdown-it Markdown parser library and the afterUpdate lifecycle method: Demo - afterUpdate Lifecycle Method - Markdown Editor Here, we have a <textarea /> element on the left for writing Markdown and a <div /> container element on the right for rendering the output of the Markdown. markdown-it provides a render method that accepts Markdown as an argument and returns the generated HTML as a string. This HTML string can be rendered as HTML using the @html template syntax . Anytime an HTML string is rendered via the @html template syntax, the HTML string should be sanitized (before rendering) to prevent cross-site scripting, especially if the original source is untrusted. Pass the result of md.render as an argument to the sanitizeHtml function of the sanitize-html library to remove malicious HTML code. Changes to the value of markdown (bound to the <textarea /> element via the bind:value directive) will trigger the afterUpdate lifecycle method, which will take this value and convert it to stringified HTML that is sanitized. This result will be rendered as HTML. As you type Markdown into the <textarea /> , the output of the Markdown will be displayed and live updated, giving you immediate feedback on your Markdown. Note : Alternatively, this same behavior can be achieved by using a reactive statement. Many websites provide a theme toggle to dynamically change their appearance based on a user's color preferences. To implement theming, use CSS variables and change the value of those variables whenever a different theme is selected. Visit this simple Svelte REPL demo to see how to toggle themes using the afterUpdate lifecycle method: Demo - afterUpdate Lifecycle Method - Theme Toggle Using a <div /> element with a class body to serve as a pseudo <body /> element, it has a background-color CSS property set to var(--background-color) and a color CSS property set to var(--color) . These theme values are pre-defined in an object themes , and whenever any of these two buttons are clicked, the toggle function is called, and the theme variable is set to either themes.dark or themes.light (depending on the button clicked). When theme is updated, the afterUpdate lifecycle method is called, and the values of the CSS variables are updated accordingly. Note : Without label in the theme object, the afterUpdate lifecycle method would not be called because the theme object would not referenced anywhere in the HTML markup of the component. Note : Alternatively, this same behavior can be achieved by using a reactive statement. From top to bottom, chat clients display messages in ascending order of their timestamp, with the oldest messages at the top and the most recent messages at the bottom adjacent to the "Send Message" input field. When a new message is received within a chat client, the user is automatically scrolled to that message at the bottom of the scrollable view, assuming that they haven't scrolled beyond a certain threshold that indicates the user browsing through older messages. Visit this simple Svelte REPL demo to see how chat clients auto-adjust a user's scroll position upon receiving a new message using the afterUpdate lifecycle method: Demo - afterUpdate Lifecycle Method - Auto-Adjust Scroll Position in Messaging Client ( ChatClient.svelte ) In this demo, there are two chat clients, one for a user named "Jesse" and another for a user named "Alex." Whenever any one of these two users sends a message, the message will be displayed in both clients since these messages are based on a conversation between these two users. Messages sent by the user are styled with a blue background and white text, while messages received by the user are styled with a light-grey background and black text. The <ChatClient /> retrieves these messages from a store: When the user submits a new message, the addMessage method will be called to concatenate a new message to the messages array, and the input field where the user types messages will be cleared. Because the messages array is modified (and is used to render messages), the beforeUpdate and afterUpdate lifecycle methods are called. beforeUpdate is called to determine whether or not to automatically scroll the user to the bottom of the <div /> container element (reference stored in messagesContainer ) to see the new message. If the user is within 20px of the bottom-most scroll position of this container element, then the shouldAutoScroll flag will be set to true , and the client will automatically scroll to the bottom of this container element so that the user can see the latest received message. This must be done before the DOM is updated with the new message because adding a new message will increase the scrollHeight by more than the 20px threshold (due a message's minimum height), and thus, cause the calculation to keep assuming that you are browsing through older messages even though you are not. Once the DOM is updated with the new message, the afterUpdate lifecycle method will be called, and it will scroll to the bottom of the container depending on the value of the shouldAutoScroll flag. To animate an element, the element must sequentially transition from a starting state to an ending state. For example, you may want to move a square from the top-left corner (starting state) of a view to the bottom-right corner (ending state) of a view. In between these two states, there may be intermediate states that the element must fulfill. For example, maybe you want the square to move in a zig-zag motion towards the bottom-right corner rather than in a straight diagonal motion. Additionally, parameters such as duration , timing function and delay must be factored into each step. Referring back to the square example, each step in the animation requires knowing the most recent (x, y) coordinates of the square's position and the (x, y) coordinates of the square's next position in the zig-zag motion. And this continues on for each adjacent pair of steps in the animation sequence. At each step, you would cache the current coordinates of the square and calculate the difference between these coordinates and the next coordinates of the square. Using the calculated displacement (and other parameters like the ones mentioned previously), the square can be animated from point A to point B. In Svelte, animating an element can be done using the beforeUpdate and afterUpdate lifecycle methods. The below snippet of code is based on a demo presented at Svelte Summit 2020: In the beforeUpdate lifecycle method, before each DOM update, the current coordinates ( x and y ) of the animating element ( node ) are cached. In the afterUpdate lifecycle method, after each DOM update, the cached coordinates are subtracted from the current coordinates to determine how far away these coordinates are from one another ( dx and dy ). Then, either a spring-based (via createSpringAnimation ) or keyframe (via createKeyframes ) animation is performed (via node.animate ) using these calculated differences ( keyframeFn({ dx, dy }) ). Visit this Svelte REPL demo to see this in action: Demo - afterUpdate Lifecycle Method - Custom Svelte Action - Shuffle Animation Note : This demo is based on the Svelte Summit 2020 demo. In this demo, pressing the "Shuffle" button randomly rearranges the cat pictures in a two column masonry grid layout (columns are 300px in width). The pictures are smoothly translated from one slot to another. Each picture <div /> element is attached element-level lifecycle methods via a Svelte action ( translate.action , prefixed with the use directive). These methods are called when the element is created, destroyed, etc. Here, translate.action is assigned the translateElement function, which contains the exact same code as previously mentioned with the beforeUpdate and afterUpdate lifecycle methods. ( translate.js ) If you continuously press the "Shuffle" button, then the pictures will be shuffled around until the "Shuffle" button is no longer pressed, at which point, the pictures will be able to animate to their designated new slots. This "shuffling around" behavior is made possible by the following code that uses the afterUpdate lifecycle method. The tick function is called ensure that all pending state changes have been reflected to the DOM. Then, translate.flush executes all of the animation steps queued via the syncLayout.read and syncLayout.write methods in the translateElement function. This allows the translation animation to be ran smoothly irregardless of interruptions. If this block of code was commented out, then the pictures would "blink" immediately to their designated new slots. Note : Alternatively, you can use one of Svelte's built-in animation directives such as flip . If you have built React applications, then you will have probably noticed how similar afterUpdate is to componentDidUpdate / useEffect . Try rewriting some of the those components that use componentDidUpdate / useEffect as Svelte components that use afterUpdate . If you want to learn more about Svelte, then check out Fullstack Svelte :

Thumbnail Image of Tutorial Svelte Lifecycle Method - afterUpdate

Svelte Single-Page Applications with Svelte Router SPA

Single-page applications (SPAs) provide user experiences that mirror those on desktop/mobile applications. Navigating from one page to the next no longer requires waiting for the browser to fully refresh the page on each transition, which keeps users engaged and productive. Because only a single page is served to a user, only certain sections of the view are dynamically updated by the browser (rather than the entire view via a full-page refresh) when the user navigates to a new page. To coordinate which sections of the view are dynamically updated for each route a user can navigate to, the single-page application must leverage a router to map these updates to each possible URL and render accordingly. When a router is added to an application powered by a modern front-end library/framework, such as React.js and Svelte, developers are able to quickly build single-page applications due to the declarative APIs offered by these libraries/frameworks. Compared to applications built with React.js, those built with Svelte are smaller (in bundle size) and faster. Svelte's compiler strips out the runtime overhead from outputted bundles and only ships the code that's needed. Additionally, Svelte does not rely on a virtual DOM and diffing algorithms (or other such techniques) for rendering updates. Instead, Svelte's compiler can determine ahead of time which parts of the application should change for a given state change, and when such state changes occur, it will surgically modify the DOM directly. While not as large as the React.js ecosystem, the Svelte ecosystem continues to grow and gain traction. When considering all of the routers in the React.js ecosystem, there are two that are often chosen for their maturity, robustness and simple-to-use APIs: @reach/router and react-router . To introduce the concept of integrating a router into a Svelte application, we will use an "easy to start with" router: svelte-router-spa . Using this router and Svelte, we will be building the following dashboard as a single-page application: To start, download this project from GitHub: This repository was scaffolded from the sveltejs/template project template, and it will contain the all of the dashboard's components and views. We will integrate svelte-router-spa into this dashboard so it can... Install svelte-router-spa as a dependency. To run the application, execute the dev script: Visit localhost:5000 in a browser. As you hover over each navigation bar item, notice that each item has an href value of / . Our objective will be to make these items link to their correct corresponding routes and render the correct page view. To preview any of the other page views, go to the src/layouts/DashboardLayout.svelte and swap out the current <Home /> view with another view. Example : Preview the <Projects /> view. ( src/layouts/DashboardLayout.svelte ) The browser should automatically refresh the application to reflect this change via hot reloading. Note that the title bar does not update to "Dashboard > Project" when the current view is <Projects /> . This also needs to be fixed. This dashboard will support the following routes: Inside of the src directory, add a routes.js file. Inside of this file, let's define the dashboard routes based on the information in the table above: ( src/routes.js ) Each object in routes represents an individual route. For each route, a URL pathname ( name ) is mapped to a Svelte component (directly via component or layout , or indirectly via redirectTo ). Next, let's add the <Router /> component to src/App.svelte to indicate the top-most area in the application where updates will be made to the application when these routes are visited. Anything outside of <Router /> will not be affected. The layout (or component) that matches the current active route will be rendered inside of <Router /> . In this case, when visiting /dashboard (or /dashboard/home , etc.), the <DashboardLayout /> will be rendered where <Router /> is placed. ( src/App.svelte ) Since <DashboardLayout /> is a layout component, it needs to define a place to render the child components defined in the nested routes of /dashboard . Let's add a <Route /> component to handle this. To render the correct child component for the current route, <Route /> must be passed information about the current route (and child routes) via the currentRoute object. This object is passed to the child components it renders. ( src/layouts/DashboardLayout.svelte ) In the browser, visit localhost:5000 . Notice the redirection to localhost:5000/dashboard/home and the <Home /> view being rendered for this route. Now visit localhost:5000/dashboard/projects . The <Projects /> view is rendered for this route. There are currently two issues with the navigation bar: First, let's pass currentRoute to the <Navbar /> component in the <DashboardLayout /> layout component: ( src/layouts/DashboardLayout.svelte ) Next, let's propagate currentRoute to the <NavbarMenu /> component in the <Navbar /> component: ( src/components/Navbar.svelte ) With the removal of the dashboardRoutes prop, we will need to directly import the list of routes into the <NavbarMenu /> component to render the navigation items. Currently, routes is not formatted properly for this task. We will need to refactor the routes.js file to export a dashboardRoutes array, which will be used only to render these navigation items, and add a custom flag ( isExcludedFromNav ) to the "projects/:id" nested route object to tell <NavbarMenu /> to not render it as an item in the navigation bar. ( src/routes.js ) Additionally, we will need to pass the currentRoute object to the <NavbarMenuItem /> component. ( src/components/NavbarMenu.svelte ) Inside of the <NavbarMenuItem /> component, the isActive flag determines whether or not to highlight the navigation item when its corresponding route is the current active route. svelte-router-spa provides a useful method for determining if a path is the current active route: routeIsActive . It accepts two arguments: In this case, we would want the match to be exact. The currentRoute has been passed to the <NavbarMenuItem /> component to trigger a reactive statement that will set the isActive flag whenever currentRoute changes. If the user clicks a navigation item, then the active status of the item should be changed to reflect the new current route. Hence, the following statement will correctly set the isActive flag whenever any of the navigation items is clicked: Alternatively, you could substitute the <a /> element with the <Navigate /> component (a wrapper around an <a /> element) from svelte-router-spa to automatically add an active class if the route specified for to is the current route. All-in-all, the following changes to the <NavbarMenuItem /> component are the most comprehensive: ( src/components/NavbarMenuItem ) Verify that the navigation items work properly. Verify that the active class automatically being set as a result of using the <Navigate /> component. Extra Challenge : Make these same adjustments to the mobile navigation bar, which can be viewed when the browser width is less than 768px. These are the files that need to be modified: src/components/NavbarMobileMenu.svelte , src/components/NavbarMobileMenuItem.svelte and src/components/Navbar.svelte . Notice that the title bar is not updated to reflect the current route as you navigate from one page to the next. Unfortunately, the currentRoute object does not provide a route label. Let's export a new method, getRouteLabel from src/routes.js to retrieve the current route's label. routesMapping.withoutParams is an object that maps a route's pathname to its label. For example, /dashboard/projects is mapped to "Projects." For routes without namedParams , getRouteLabel will check routesMapping.withoutParams for an exact pathname match and return a label for the matched pathname. For routes with namedParams , getRouteLabel will check an array of [ regular expression, label ] pairs and test the pathname against each pair's regular expression. The label of the first test that evaluates to true will be returned. If no matching routes are found, then an empty string is returned as the label. Import getRouteLabel into the <TitleBar /> component, and set its value to currentRouteLabel via a reactive statement. This ensures the value of currentRouteLabel is updated whenever currentRoute has changed. ( src/components/TitleBar.svelte ) Verify that the title bar is updated whenever a navigation bar item is clicked. Let's apply the same reactive statement to each view component to render the correct label in the placeholder content. ( src/views/Board.svelte , src/views/Calendar.svelte , ..., src/views/Timeline.svelte ) Verify that the correct label is rendered. Currently, the "Edit" link for a project listed under /dashboard/projects loads the "Home" view at /dashboard/home . Let's modify the link to load the "Project Info" view at /dashboard/projects/<id> . First, pass the currentRoute object to the <ProjectsTable /> component: ( src/views/Projects.svelte ) Inside of the <ProjectsTable /> component, swap out the <a /> element for the <Navigate /> element. Prefix the link with currentRoute.path . ( src/components/ProjectsTable.svelte ) Verify that clicking on "Edit" loads the "Project Info" view. Inside of package.json , there is a start script to run the production-optimized application. ( package.json ) It uses sirv , which spins up a server to allow you to preview the assets in a specified directory (in this case, public ). Passing the -s option to sirv tells it to treat the public directory as a single-page application. When you refresh the page at a route defined by the router, the route is unknown to sirv , so it will automatically serve the index.html file, which knows how to handle this route. Without this option, this will be loaded in your browser: Inside of routes.js , check if any of the defined routes has layout or component set to a string instead of an imported component. Example : ( src/routes.js ) Notice DashboardLayout is wrapped in quotes. Remove those quotes. Inside of rollup.config.js , pass the following options to the commonjs plugin: ( rollup.config.js ) Experiment! Visit the svelte-router-spa documentation and try adding protected routes to the project. If you want to learn more about Svelte, then check out Fullstack Svelte :

Thumbnail Image of Tutorial Svelte Single-Page Applications with Svelte Router SPA

Comparing Lifecycle Methods - React.js and Svelte

Modern applications involve many DOM manipulations. Components (and elements) are constantly being removed, added, updated, etc. to deliver incredible user experiences and/or to optimize performance. Sometimes, you may need to execute code when a component is added (such as automatically focusing an input field when a form is loaded like the G-Mail login page) or when a component is removed (such as removing all event listeners associated with that element to prevent memory leaks). Frameworks/libraries such as React.js and Svelte provide component lifecycle methods that allow developers to predictably execute code at these very moments/situations. Having such access into each stage a component undergoes provides more control over how and when the component should be rendered. Commonly, functions can be scheduled to be invoked when these events occur in the lifecycle of a component instance: Svelte offers four lifecycle methods: This is the order of phases for a cycle involving beforeUpdate and afterUpdate : Additionally, only one lifecycle method is ran during server-side rendering: Coincidentally, the lifecycle methods of Svelte and React.js are quite similar: Notice that all of these methods happen as soon as the component's data is updated (either new props are received or state has changed) and before any rendering occurs. As previously mentioned, beforeUpdate is also called after the props or state has been modified and before the DOM is updated. Essentially, beforeUpdate can be customized to perform the same duties as any of these three lifecycle methods. To explore these similarities in-depth and understand why lifecycle methods are important in the development of components, let's walkthrough two versions of a simple application (one version using React.js and another using Svelte) and observe these lifecycle methods. Open both demos side-by-side, and open the developer console for both. React Demo Svelte Demo The application is a simple form that asks the user if they have any allergies. If they do, then an input field asking the user to mention their allergies appears beneath the radio button group. The lifecycle methods are located in the <FormInput /> component, and each method will log a message to the console when it is executed. Note : In the React demo, you will notice two different versions of the <FormInput /> component: src/FormInput_Class.js and src/FormInput_Hooks.js . In this post, we will be using the src/FormInput_Class.js version of the component since the useEffect hook only encompasses the lifecycle methods componentDidMount , componentDidUpdate and componentWillUnmount . Feel free to use this version of the component. Answer "Yes" to the question by clicking the "Yes" option in the radio button group. The input field should appear beneath the radio button group, like so: Check the developer consoles. When a component is mounted in Svelte, it will call beforeUpdate before the initial onMount . Then, once the component has rendered, onMount is called, followed by afterUpdate . The additional beforeUpdate call is caused by the readonly this binding ( bind:this ) that references the input field ( inputElement ). When a component is mounted in React, it will call getDerivedStateFromProps before the initial mount (before the render method is called). Then, once the component has rendered, componentDidMount (the React equivalent of Svelte's onMount ) is called. Type the letter "a" into the input field. Check the developer consoles. When a component's state is changed in Svelte, it will call beforeUpdate , followed by afterUpdate . Notice that the "X" button that appears when the input contains text is not yet rendered into the DOM when beforeUpdate is called. Once beforeUpdate finishes, the DOM is updated with the new state, and then afterUpdate is executed and has access to this newly rendered "X" button. When a component's state is changed in React, it will call getDerivedStateFromProps (always called before the render method), followed by shouldComponentUpdate and getSnapshotBeforeUpdate . Notice that the "X" button is not yet rendered into the DOM when any of these methods are called (like beforeUpdate ). Once these methods finish, the render method is called, the DOM is updated with the new state, and then componentDidUpdate (the React equivalent of Svelte's afterUpdate ) is executed and has access to this newly rendered "X" button. Inside of the input field, clear it by pressing the "X" button on the right. Check the developer consoles. Basically, the same methods are called in the exact same order. The only difference here is that the "X" button has not yet been removed from the DOM when beforeUpdate (also getDerivedStateFromProps , shouldComponentUpdate and getSnapshotBeforeUpdate ) are called. Once the component re-renders and the "X" button is removed, afterUpdate (also componentDidUpdate ) recognize that this button is removed. Answer "No" to the question by clicking the "No" option in the radio button group. Check the developer consoles. When a component is unmounted ("destroyed") in Svelte, it will call onDestroy , followed by the unmount method returned from onMount . Since both methods are called just before the component is unmounted, the component (and its constituent elements) are still in the DOM when these methods are called. Once these methods finish, the component will no longer exist in the DOM. Essentially, both of these methods perform the same function, but onDestroy can run inside a server-side component unlike the unmount method returned from onMount . When a component is unmounted in React, it will call componentWillUnmount . This method, like onDestroy , is called just before the component is unmounted, so the component (and its constituent elements) are still in the DOM when it is called. Once this method finishes, the component will no longer exist in the DOM. Experiment! Apply these lifecycle methods in your Svelte applications! Build custom Svelte lifecycle methods using beforeUpdate , afterUpdate , onMount and onDestroy .

Thumbnail Image of Tutorial Comparing Lifecycle Methods - React.js and Svelte