Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 80 additions & 82 deletions src/routes/(3)configuration/(1)typescript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,83 @@ In the type signature `JSX.EventHandler<T, E>`, `currentTarget` will consistentl
However, the type of target could be more generic, potentially any DOM element.
For specific events like `Input` and `Focus` that are directly associated with input elements, the target will have the type `HTMLInputElement`.

#### The `on:` directive

The `on:___` attribute provides low-level access to native DOM `addEventListener`, allowing custom event types and listener options.

##### Custom events

To handle custom events, extend Solid's JSX namespace with the `CustomEvents` interface:

```tsx
class NameEvent extends CustomEvent<{ name: string }> {
constructor(name: string) {
super("Name", { detail: { name } });
}
}

declare module "solid-js" {
namespace JSX {
interface CustomEvents {
Name: NameEvent; // Matches `on:Name`
}
}
}

// Usage
<div on:Name={(event) => console.log("name is", event.detail.name)} />;
```

:::note

<span>New in v1.9.0</span>
:::

It is now possible to use the intersection `EventListenerObject & AddEventListenerOptions` to provide listener options as follows:

```tsx
import type { JSX } from "solid-js";

const handler: JSX.EventHandlerWithOptions<HTMLDivElement, Event> = {
once: true,
handleEvent: (event) => {
console.log("will fire only once");
},
}

// Usage
<div on:click={handler} />;
```

##### Using native events with `on:`

By default, using native events like `mousemove` with the `on:` prefix — for example, `<div on:mousemove={e => {}} />` — will trigger a TypeScript error.
This occurs because these native events are not part of Solid's custom event type definitions.
To solve this, the `CustomEvents` interface can be extended to include events from the `HTMLElementEventMap` (which covers HTML element events — not `Document` or `Window` events).

To include all native events:

```ts
declare module "solid-js" {
namespace JSX {
interface CustomEvents extends HTMLElementEventMap {}
}
}
Comment on lines +502 to +506
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Added a parenthetical note: 'which covers HTML element events -- not Document or Window events'.

```

To include specific native events, you can choose certain events (e.g. `mousemove` and `pointermove`):

```ts
declare module "solid-js" {
namespace JSX {
interface CustomEvents extends Pick<
HTMLElementEventMap,
"mousemove" | "pointermove"
> {}
}
}
```

### `ref` attribute

#### Basics
Expand Down Expand Up @@ -632,86 +709,7 @@ The following alternative also works when using `Show`:

## Advanced JSX attributes and directives

### Custom event handlers

To handle custom events in Solid, you can use the attribute `on:___`.
Typing these events requires an extension of Solid's JSX namespace.

```tsx
class NameEvent extends CustomEvent {
type: "Name";
detail: { name: string };

constructor(name: string) {
super("Name", { detail: { name } });
}
}

declare module "solid-js" {
namespace JSX {
interface CustomEvents {
Name: NameEvent; // Matches `on:Name`
}
}
}

// Usage
<div on:Name={(event) => console.log("name is", event.detail.name)} />;
```

:::note

<span>New in v1.9.0</span>
:::

It is now possible to use the intersection `EventListenerObject & AddEventListenerOptions` to provide listener options as follows:

```tsx
import type { JSX } from "solid-js"

const handler: JSX.EventHandlerWithOptions<HTMLDivElement, Event> = {
once: true,
handleEvent: (event) => {
console.log("will fire only once");
},
}

// Usage
<div on:click={handler} />;
```

:::note
**Note**:
By default, using native events like `mousemove` with the `on` prefix — for example, `<div on:mousemove={e => {}} />` — will trigger a TypeScript error.
This occurs because these native events are not part of Solid's custom event type definitions.
To solve this, the `CustomEvents` interface can be extended to include events from the `HTMLElementEventMap`:

To include all native events:

```ts
declare module "solid-js" {
namespace JSX {
interface CustomEvents extends HTMLElementEventMap {}
}
}
```

To include specific native events, you can choose certain events (e.g. `mousemove` and `pointermove`):

```ts
declare module "solid-js" {
namespace JSX {
interface CustomEvents extends Pick<
HTMLElementEventMap,
"mousemove" | "pointermove"
> {}
}
}
```

:::

#### Forcing properties and custom attributes
### Forcing properties and custom attributes

In Solid, the `prop:___` directive allows explicit property setting, which is useful for retaining the original data types like objects or arrays.
`attr:___` directive allows custom attributes, on the other hand, and it is effective for handling string-based HTML attributes.
Expand All @@ -738,7 +736,7 @@ declare module "solid-js" {
<my-web-component attr:name={name()} attr:count={count()} bool:disabled={true}/>
```

#### Custom directives
### Custom directives

In Solid, custom directives can be applied using the `use:___` attribute, which usually accepts a target element and a JSX attribute value.
The traditional `Directives` interface types these values directly (i.e. the type of `value` in `<div use:foo={value} />`).
Expand Down Expand Up @@ -823,7 +821,7 @@ While the `Directives` interface can limit the value type passed via JSX attribu
<div use:model={createSignal('')} />
```

##### Addressing import issues with directives
#### Addressing import issues with directives

If directives are imported from a separate file or module, TypeScript might mistakenly remove the import thinking it is a type.

Expand Down
Loading