12

After loading the component that has input filed inside it. How can I focus on that particular field?

TextField.svelte

<script>

  export let label = ''
  export let name = ''
  export let placeholder = ''
  export let value = ''

</script>

<div class="field">
  <label for={name}>{label}</label>
  <input {placeholder} type="text" {name} bind:value={value} >
  <slot></slot>
</div>

App.svelte

<script>
  import TextField from './TextField'
  import {onMount} from 'svete'

  onMount(() => {
    // This line is funny.. I know
    document.querySelector('[name="firstname"]').focus()
  })

</script>

<TextField label="First Name" name="firstname" />
2

3 Answers 3

18

You can get a reference to the input DOM node with bind:this and export it as a prop and use it in the parent component.

Example

<!-- TextField.svelte -->
<script>
  export let label = '';
  export let name = '';
  export let placeholder = '';
  export let value = '';
  export let ref = null;
</script>

<div class="field">
  <label for={name}>{label}</label>
  <input {placeholder} type="text" {name} bind:value={value} bind:this={ref} >
  <slot></slot>
</div>

<!-- App.svelte -->
<script>
  import TextField from './TextField.svelte';
  import { onMount } from 'svelte';
    
  let ref;
    
  onMount(() => {
    ref.focus(); 
  });      
</script>

<TextField label="First Name" name="firstname" bind:ref />
Sign up to request clarification or add additional context in comments.

4 Comments

Have you tried this code? ref.focus() doesn't seem to work for me whereas I'm able to change other properties of element using ref.
What is 'ref' short for? It might be clearer to use a better variable name.
@mikemaccana - ref just short for reference, but it's commonly used in this context so for the sake of an example should be fine.
@Lissy93 what is ref a reference to? An element (just guessing)? It would be clearer to use textfield or textfieldElement or some other full word.
7

You have several typos actually in the App.svelte.

First, importing the component.

import TextField from './TextField'

That should be:

import TextField from './TextField.svelte';

Second, the Svelte package itself.

import {onMount} from 'svete'

That should be:

import { onMount } from 'svelte';

Okay, now we are ready to code.

Since autofocus attribute should be avoided, we may use Tholle's answer as reference.

In the TextField.svelte, you handle the autofocus.

<script>
    import { onMount } from 'svelte';

    export let focused = false;
    export let label = '';
    export let name = '';
    export let placeholder = '';
    export let value = '';

    let elm;

    onMount(function() {
        elm.focus();
    });
</script>

<div class="field">
    <label for={name}>{label}</label>
    <input {placeholder} type="text" {name} bind:value={value} bind:this={elm}/>
    <slot/>
</div>

In the App.svelte, you call the component.

<script>
  import TextField from './TextField.svelte';
</script>

<TextField label="First Name" name="firstname" focused/>
<TextField label="Last Name" name="lastname" focused/>

The demo available on the Svelte REPL.

The difference between my answer and Tholle's is that focus() should be executed in the TextField component since it is component specific functionality.

3 Comments

Not editing my question for silly typos so that the precious lines you wrote remain relevant :)
Notice that it's not the autofocus attribute that should be avoided, but rather autofocus itself, which is what this answer does anyway. All this does is get rid of the warning. Also, you should have an await tick() before calling focus otherwise your element may not exist. Lastly, you probably wanted to check for if (focused) before calling elm.focus(), otherwise that prop is useless.
You'd think the autofocus attribute would be encouraged, and then screen readers could simply ignore it. But I guess simple solutions are also discouraged. :)
5

You can use the autofocus attribute.

<script>

  export let label = ''
  export let name = ''
  export let placeholder = ''
  export let value = ''

</script>

<div class="field">
  <label for={name}>{label}</label>
  <input {placeholder} type="text" {name} bind:value={value} autofocus > // <-- here
  <slot></slot>
</div>

But as stated in this answer, it's probably not a good idea from an accessibility standpoint.

1 Comment

Nowadays that'll trigger a warning: A11y: Avoid using autofocussvelte(a11y-autofocus). So as the OP stated, probably not the way to go.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.