Skip to content

Latest commit

 

History

History

readme.md

Context

Table of contents

Type-safe context

If you use createContext, wrap your component in a wrapper function to create the context.

Note

Setting a context value in a wrapper function requires svelte>=5.50.0.

typesafe-context.ts

import { createContext } from 'svelte'

export interface Message {
  id: string
  text: string
}

export interface MessagesContext {
  current: Message[]
}

export const [getMessagesContext, setMessagesContext] =
  createContext<MessagesContext>()

typesafe-context.svelte

<script lang="ts">
  import { getMessagesContext } from './typesafe-context.js'

  let { label } = $props()

  const messages = getMessagesContext()
</script>

<div role="status" aria-label={label}>
  {#each messages.current as message (message.id)}
    <p>{message.text}</p>
    <hr />
  {/each}
</div>

typesafe-context.test.js

import { render, screen } from '@testing-library/svelte'
import { expect, test } from 'vitest'

import { type MessagesContext, setMessagesContext } from './typesafe-context.js'
import Subject from './typesafe-context.svelte'

test('notifications with messages from context', () => {
  const messages: MessagesContext = {
    get current() {
      return [
        { id: 'abc', text: 'hello' },
        { id: 'def', text: 'world' },
      ]
    },
  }

  const Wrapper: typeof Subject = (...args) => {
    setMessagesContext(messages)
    return Subject(...args)
  }

  render(Wrapper, { label: 'Notifications' })

  const status = screen.getByRole('status', { name: 'Notifications' })

  expect(status).toHaveTextContent('hello world')
})

Context with key

If you use setContext and getContext, you can use the context option of render to pass a context in. When using extra component options like context, be sure to place props under the props key.

context.svelte

<script>
  import { getContext } from 'svelte'

  let { label } = $props()

  const messages = getContext('messages')
</script>

<div role="status" aria-label={label}>
  {#each messages.current as message (message.id)}
    <p>{message.text}</p>
    <hr />
  {/each}
</div>

context.test.js

import { render, screen } from '@testing-library/svelte'
import { expect, test } from 'vitest'

import Subject from './context.svelte'

test('notifications with messages from context', () => {
  const messages = {
    get current() {
      return [
        { id: 'abc', text: 'hello' },
        { id: 'def', text: 'world' },
      ]
    },
  }

  render(Subject, {
    context: new Map([['messages', messages]]),
    props: { label: 'Notifications' },
  })

  const status = screen.getByRole('status', { name: 'Notifications' })

  expect(status).toHaveTextContent('hello world')
})