Linguine Code

How to pass input value from child component to parent component

If you’re coming from React, passing a value from a child component to the parent component requires some boilerplate code.

You can see an example here.

I’m going to replicate the the example in the link above, but in Svelte.

I’m going to create a Svelte component called input.svelte.


<script>
  // Creating a prop
  export let onChange;

  const handleBlur = e => {
    if ('function' === typeof onChange) {
      // Pass input value to the top
      onChange(e.target.value);
    }
  };
</script>

<input on:blur={handleBlur}>

In my Input component, I have a handleBlur() function. The sole job of this function is to check if onChange is a function, and if so, pass the input value through.

In my parent Svelte component, App.svelte, I’m going to import my Svelte Input component, and attach a function handler to the onChange prop.


<script>
  import Input from "./input.svelte";

  let fullName = "";

  // Update fullName when the value changes on blur event
  const handleChange = value => (fullName = value);
</script>

<label>
  Enter your name
  <Input onChange={handleChange} />
</label>

<h1>Hi {fullName}!</h1>

handleChange() is responsible to update the state property fullName.

The greeting message then displays the new name value.

This works fine, but there are 2 problems:

  • It doesn’t feel real time because it happens when the input tag is out of focus
  • Too much boilerplate code

To solve for the 2 problems above, I can use Svelte bind:property feature to help our Svelte app stay reactive on change.

Use bind:property instead of handler functions

In Svelte data flows downward. But sometimes you need data to flow upwards to a parent component.

And the example above we did that by tossing event handler functions down, to get values to go up to the parent component.

But, bind:property={variable} let’s us reduce that boilerplate code, and gives us that real-time update.

It continues to follow the “write less, do more” motto.

Let’s refactor the Input component and use the bind property.


<script>
  // Input prop called value
  export let value;
</script>

<input type="text" bind:value>

The only thing in the <script> tag is an exported variable called value.

I’m than updating the input HTML element to bind with the variable, value.

Since the export variable name was the same name as the bind property, I used the short-hand version.


<!-- long-hand version -->
<input type="text" bind:value={value}>

<!-- short-hand version -->
<input type="text" bind:value>

Now I’m going to refactor the App.svelte component and make use of the new bind:property feature.


<script>
  import Input from "./input.svelte";

  let fullName = "";
</script>

<label>
  Enter your name
  <input bind:value={fullName}>
</label>

<h1>Hi {fullName}!</h1>

Let’s do a quick breakdown on this file.

I deleted the handler function, handleChange(), and left the import statement and the state variable, fullName.


<script>
  import Input from "./input.svelte";

  let fullName = "";
</script>

The next update in App.svelte, was the Input component directive.


<Input bind:value={fullName}>

On the directive, I also added bind:value={fullName} so it keeps my state variable, fullName, updated as the user is entering new characters.

Now every time you enter a new character inside the text field, it will update the output greeting message.