---
title: Synchronous Event Processing | Tutorial
contributors:
  - adamdbradley
  - manucorporat
  - kerbelp
  - mhevery
  - cunzaizhuyi
  - spenserblack
  - hamatoyogi
  - mrhoodz
updated_at: '2023-06-25T19:43:33Z'
created_at: '2022-08-02T12:07:45Z'
---

While not a common use case, you may occasionally need to process events synchronously.

The two most common use cases are to call `event.preventDefault()` or `event.stopPropagation()` on a DOM event. Those are handled by adding the `preventdefault:eventname` or `stoppropagation:eventname` in addition to your event handler.

```tsx
  <a href="/" preventdefault:click onClick$={() => {
    console.log('clicked');
  }}>
    link
  </a>
```

When you have other use cases that require synchronous event processing, you can use either `sync$()` or `useVisibleTask$()`.
1. preferred way: use `sync$()` to embed the code in the HTML. Fast, resumable, but with some restrictions (see below).
2. eager registration: use `useVisibleTask$()` to register a handler. No restrictions, but it will not handle events until the visible task has executed, and it will cause of course run extra javaScript while the page is loading.

```tsx
  <a href="/" 
    onClick$={sync$((event, target) => {
      // Only prevent default if the ctrl key is pressed.
      if (event.ctrlKey) {
        event.preventDefault();
      }
    })}>
    link
  </a>
```

## `sync$()` Restrictions

The `sync$()` function is a resumable way to process events synchronously. However, it has some significant restrictions. The `sync$()` **can't close over anything**. The implications are that you can't:
- access any state: The recommended way to get the state into function is to place on element attributes.
- access any non-browser functions: No imports or closing over any variables or functions are allowed. 
- the function should be small as it will get inlined into the resulting HTML.

For this reason, we recommended breaking up the event handlers into two parts:
1. **sync$()**: The part which must be synchronous. This part should be small and not close over anything.
2. **$()**: The part which can be asynchronous. This part can be large and can close over anything including the state.

```tsx
  <a href="/" 
    onClick$={[
      sync$((event, target) => {
        // This part is synchronous and can't close over anything.
        if (event.ctrlKey) {
          event.preventDefault();
        }
      }),
      $(() => {
        // This part can be asynchronous and can close over anything.
        console.log('clicked');
      })
    ]}>
    link
  </a>
```

You can also dispatch a custom event from the `sync$()` handler and handle it asynchronously:

```tsx
  <a href="/" 
    onClick$={sync$((event, target) => {
      if (event.ctrlKey) {
        event.preventDefault();
      }
      // Dispatch a custom event to be handled asynchronously.
      target.dispatchEvent(new CustomEvent('myclick', { bubbles: true }));
    })}
    onMyclick$={() => {
      // This part can be asynchronous and can close over anything.
      console.log('clicked');
    }}>
    link
  </a>
```

 **Your task:** Convert the `onClick$` from asynchronous event to synchronous event by using [`sync$`](/docs/(qwik)/core/tasks/index.mdx#usevisibletask).
