---
title: "JSX"
image: "https://hem.run/social/hem.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://hem.run/llms.txt
> Use this file to discover all available pages before exploring further.

# JSX

JSX parses natively and passes through to `.tsx` untouched. React's own type checking applies, `jsxImportSource` is read from your tsconfig, and every file may contain JSX. Hem supports expressions inside the braces:

```hem
let Badge = ({ state }: { state: PaymentState }) =>
  <span className={match state {
| Paid(_) => "green"
| Refunded(_) => "red"
| _ => "gray"
  }}>
{label(state)}
{if state == Pending { <Spinner size="sm" /> }}
  </span>
```

`{if cond { <X/> }}` is the conditional-rendering idiom: typed `?Element`, and absent values render nothing. It replaces `{cond && <X/>}`, which boolean-only `&&` forbids, preventing truthiness issues such as `{items.length && ...}` rendering a `0`. Attributes also support unbraced forms: a bare name **puns** the in-scope binding, `name?` puns an optional, and simple values go unbraced:

```hem title="user-card.hem"
<UserCard user compact subtitle?=bio onSelect=select(user.id) />
```

```tsx emitted title="user-card.tsx — generated"
<UserCard user={user} compact={compact} {...(bio === null || bio === undefined ? {} : { subtitle: bio })} onSelect={select(user.id)} />
```

The optional pun lowers to a conditional spread rather than `subtitle={undefined}` on purpose: when the value is absent the prop is **omitted**, so `exactOptionalPropertyTypes` holds and React default props still apply.

`<input checked />` passes your `checked` binding, not React's implicit `true`. Write `checked={true}` for a literal boolean. Values with operators keep braces (JSX's `>` and `/` are closing tokens); children are unchanged TSX: text by default, `{}` for expressions.

Source: https://hem.run/tour/jsx/index.mdx
