Skip to content
On this page

Chapter 2 - Your First Component

The Items List

Let's now pretend we have been giving requirements for our app to have a component that displays a list of "items". We will keep this simple initially and as we move towards more advanced chapter expand on it to show how we can better structure our application to support:

  • Quick prototyping and development using mocked data
  • Component Organization
  • Unit Testing
  • State Management
  • Internationalization support so we can render our user interface using different languages
  • Localization for number and date formatting for different cultures

ItemsList Component Requirements

Your initial version of the ItemsList component, will have to implement the following requirements (later, in more advanced chapters, we will expand on these as we get into more advanced topics):

  • The component will display a list of items

  • An item will have 3 properties:

    • id
    • name
    • selected
  • The item name will be displayed to the user

  • The user should be able to select/deselect one or more item

  • An icon will be shown next to the name to indicate if the item is selected

ItemsList Component Code

Within the src/components directory, create a sub-directory called items. Within this folder add a new file called ItemsList.component.svelte[1]

Your directory structure will now look like this:

Within the ItemsList.component.svelte file, paste the following code:

html
// file: src/components/items/ItemsList.component.svelte

<script lang="ts">
  // expose a property called items with a default value of a blank array
  export let items: any[] = [] // explicetely using any[] as we'll replace this with an interface in the next chapters
</script>

<div>
  <h3>Items:</h3>
  <ul>
    {#each items as item}
      <li>
        {item.name}
      </li>
    {/each}
  </ul>
</div>

A few things to notice here. First, we specify the lang attribute on the <script> element with the value ts so we can use TypeScript. We export a variable called items. This is how we create a component property in Svelte[2]. Note that items is just using the type any[3] for now (later we'll replace any with an interface we'll create).

For our html template, we added a <h3> element with hard-coded text just saying "Items:". Then a <ul> with a #each binding that will render all our items within <li> elements.

App.svelte

Open the existing App.svelte file. Replace the existing code with this:

html
// file: src/App.svelte

<script lang="ts">
 // TODO ....
</script>
<main>
  <div class="home">
   ... TODO
  </div>
</main>

Within <script> the section, import a reference to the ItemsListComponent:

html
// file: src/App.svelte

<script lang="ts">
  // import a reference to our ItemsList component
  import ItemsListComponent from './components/items/ItemsList.component.svelte'
...

For now, also mock some data for our list of items that we will feed to our ItemsListComponent. For this we instantiate a local const called items and initialize it with some hard-coded data[4]. Let;s just add it after the import statement:

html
// file: src/App.svelte

<script lang="ts">
  // import a reference to our ItemsList component
  import ItemsListComponent from './components/items/ItemsList.component.svelte'

  // mock some data:
  const items: any[] = [{ // explicetely using any[] as we'll replace this with an interface in the next chapters
    id: 1,
    name: 'Item 1'
  }, {
    id: 2,
    name: 'Item 2'
  }, {
    id: 3,
    name: 'Item 3'
  }]
</script>
...

Finally, we add an <ItemsListComponent> element within the <main> markup. Insert it within the <div class="home"> element. Add an attribute called items to our <ItemsListComponent>. This is how we pass properties to from parent to child components in Svelte[5]. The items data is fed into the component items property this way. The complete code within the App.svelte file should now look like this:

html
// file: src/App.svelte

<script lang="ts">
  // import a reference to our ItemsList component
  import ItemsListComponent from './components/items/ItemsList.component.svelte'

  // mock some data:
  const items: any[] = [{
    id: 1,
    name: 'Item 1'
  }, {
    id: 2,
    name: 'Item 2'
  }, {
    id: 3,
    name: 'Item 3'
  }]
</script>

<main>
  <div class="home">
    <ItemsListComponent items={items}/>
  </div>
</main>

Comment out or remove the app.css import reference from the src/main.ts file:

typescript
// import './app.css' // <-- remove this line
import App from './App.svelte'

const app = new App({
  target: document.getElementById('app')
})

export default app

Save the file. The web browser will refresh and display our preliminary items list being rendered more or less like this:

Chapter 2 Recap

What We Learned

  • How to create a basic component that displays a list of items
  • How to consume that component from another component/view

Observations

  • The items property within the ItemsList.component.svelte is declared as an array of type any
  • The App.svelte view contains hard-coded data (items) which is also declared as an array of any
  • This means we are not leveraging strong-type checking at development time using TypeScript interfaces/models/types

Based on these observations, there are a few improvements that we will make in the next chapters:

Improvements

  • Create a TypeScript interface called ItemInterface for enforcing type checking at development time for our items data
  • Update our code so it uses the new ItemInterface interface

  1. We are following a file naming convention where higher level components' names are pascal-case and follow this format [ComponentName].component.svelte (Reference: Naming Conventions section at the end of this book) ↩︎

  2. https://svelte.dev/docs#component-format-script-1-export-creates-a-component-prop ↩︎

  3. With 'any', TypeScript does not enforce type-checking on a property or variable. However, this is considered a bad practice as we lose the main benefit of TypeScript. There might be exceptions to this rule when using older 3rd party packages/libraries/plugins that do not offer type definitions. However, even in those cases it would be strongly recommended to provide interfaces and types so that you can still avoid using 'any'. ↩︎

  4. Note: using hard-coded data is a bad practice and here we are only doing it to first illustrate how things flow, and later in the next chapters will remove in favor of best practices and patterns (see Chapter 5) ↩︎

  5. https://svelte.dev/docs#template-syntax-attributes-and-props ↩︎

This is a sample from the book.