# Elements
JSX expressions and the element builder API can be used to directly create DOM elements:

=== "JSX"
	```jsx
	<div class="example">Hello World!</div>
	```

=== "No Build"
	```jsx
	import { e } from "./rvx.js";

	e("div").class("example").append("Hello World!")
	```

## Attributes
Attributes are set using `setAttribute` or `removeAttribute` by default.

+ Attributes set to `null`, `undefined` or `false` are removed.
+ Attributes set to `true` are set as an empty string.
+ All other values are set as strings.

=== "JSX"
	+ Attributes prefixed with `prop:` are always set using the respective JavaScript properties.
	+ Attributes prefixed with `attr:` are always set using the default behavior.
	+ Attributes prefixed with `on:` are added as event listeners.
		+ An array can be used to pass the event listener with additional options.
		+ The current [context](./context.md) is available within the listener.
	+ The [`class`](#classes) and [`style`](#styles) attributes are special cases described below.

	```jsx
	// Using setAttribute:
	<input value="Example" />

	// Using the "value" property:
	<input prop:value="Example" />

	// Setting a boolean attribute:
	<input disabled />;
	<input disabled={true} />

	// Removing a boolean attribute:
	<input disabled={false} />

	// Adding event listeners:
	<button on:click={event => { ... }} />
	<button on:click={[event => { ... }, { capture: true, passive: true }]} />
	```

=== "No Build"
	```jsx
	// Using setAttribute:
	e("input").set("value", "Example")

	// Using the "value" property:
	e("input").prop("value", "Example")

	// Setting a boolean attribute:
	e("input").set("disabled", true)

	// Removing a boolean attribute:
	e("input").set("disabled", false)

	// Adding event listeners:
	// (The current context is available within the listener)
	e("input").on("click", event => { ... })
	e("input").on("click", event => { ... }, { capture: true, passive: true })
	```

Attribute values can be [expressions](signals.md#expressions).

=== "JSX"
	```jsx
	// Static values:
	<div title="Hello World!" />
	<div title={"Hello World!"} />

	// Signals:
	<div title={someSignal} />

	// Functions:
	<div title={() => someSignal.value} />
	```

=== "No Build"
	```jsx
	// Static values:
	e("div").set("title", "Hello World!")

	// Signals:
	e("div").set("title", someSignal)

	// Functions:
	e("div").set("title", () => someSignal.value)
	```

Note, that the rules specified above apply to all attributes including aria attributes. To set an attribute to the literal `"true"` and `"false"` strings, you can convert an arbitrary [expression](signals.md#expressions) using `string` or `optionalString`:

=== "JSX"
	```jsx
	import { string, optionalString } from "rvx/convert";

	// Convert all values to strings including "null" and "undefined":
	<div aria-disabled={string(someBooleanExpression)} />

	// Convert values to strings excluding "null" or "undefined":
	<div aria-disabled={optionalString(someBooleanExpression)} />
	```

=== "No Build"
	```jsx
	import { e } from "./rvx.js";
	import { string, optionalString } from "./rvx.convert.js";

	// Convert all values to strings including "null" and "undefined":
	e("div").set("aria-disabled", string(someBooleanExpression))

	// Convert values to strings excluding "null" or "undefined":
	e("div").set("aria-disabled", optionalString(someBooleanExpression))
	```

## Classes
The `class` attribute can be any combination of class tokens, arrays and objects with boolean [expressions](signals.md#expressions) to determine which classes are added. `undefined`, `null` and `false` is ignored.

=== "JSX"
	```jsx
	<div class="example" />
	<div class={[
		"foo",
		() => "bar",
		{
			baz: true,
			boo: () => false,
		},
	]} />
	```

	To avoid this special behavior, you can use the `attr:` prefix:
	```jsx
	<div attr:class="example">
	```

=== "No Build"
	```jsx
	e("div").class("example")

	e("div").class([
		"foo",
		() => "bar",
		{
			baz: true,
			boo: () => false,
		},
	])
	```

	To avoid this special behavior, you can use the `set` function:
	```jsx
	e("div").set("class", "example")
	```

## Styles
The **style** attribute can be any combination of arrays, objects and [expressions](signals.md#expressions).

Properties use the same casing as in css. E.g. `font-family`, not `fontFamily`.

=== "JSX"
	```jsx
	<div style={{ color: "red" }} />
	<div style={[
		{
			"color": "red",
			"font-size": "1rem",
		},
		() => ({ "color": () => "blue" }),
		{ "color": someSignal },
		[
			{ "width": "42px" },
		],
	]} />
	```

	To avoid this special behavior, you can use the `attr:` prefix:
	```jsx
	<div attr:style="color: red;">
	```

=== "No Build"
	```jsx
	e("div").style({ color: "red" })
	e("div").style([
		{
			"color": "red",
			"font-size": "1rem",
		},
		() => ({ "color": () => "blue" }),
		{ "color": someSignal },
		[
			{ "width": "42px" },
		],
	])
	```

	To avoid this special behavior, you can use the `set` function:
	```jsx
	e("div").set("style", "color: red;");
	```

Note, that properties that are no longer specified after a signal update are not reset automatically to keep the current implementation simple. When properties are specified multiple times, the last one has priority used.

## References

=== "JSX"
	To get the reference to an element, you can either use the JSX expression directly:

	```jsx
	const input = <input /> as HTMLInputElement;
	```

	Or use the special `ref` attribute:
	```jsx
	<input ref={input => { ... }} />;
	```

	All attributes (except `key`) are processed in the specified order. In the example below, the `ref` function is called after `data-a` is set, but before `data-b` is set:
	```jsx
	<input data-a ref={input => { ... }} data-b />;
	```

=== "No Build"
	To get references to an element, you can reference the builder's `elem` property.

	```jsx
	const input = e("input").elem;
	```

## Content
Everything listed below can be used as element content or can be returned from [component](components.md) functions.

### Text
Expressions (static values, signals and functions) are rendered as escaped text content. `null` and `undefined` are rendered as an empty string:

=== "JSX"
	```jsx
	<div>
		Static text
		{"Static text"}
		{someSignal}
		{() => someSignal.value}
	</div>
	```

=== "No Build"
	```jsx
	e("div").append(
		"Static text",
		someSignal,
		() => someSignal.value
	)
	```

### Nodes
Any DOM nodes are moved into the parent element.

=== "JSX"
	```jsx
	<div>
		<input />
		{document.createElement("div")}
	</div>
	```

=== "No Build"
	```jsx
	e("div").append(
		e("input"),
		document.createElement("div")
	)
	```

Note, that nodes are removed from their parent depending on when the content is actually used in an element. E.g. when returning a document fragment from a [component](components.md), it's children are removed from the fragment as soon as the components return value is used in an element expression.

Reusing DOM nodes may result in undefined behavior. Consider using [`movable`](./views/movable.md) for safely reusing & moving arbitrary content.

If objects have a `NODE` symbol property, this node is used instead. This is internally used by the builder API, but you can also implement your own:

=== "JSX"
	```jsx
	import { NODE } from "rvx";

	<div>
		{{ [NODE]: document.createElement("div") }}
	</div>
	```

=== "No Build"
	```jsx
	import { NODE, e } from "./rvx.js";

	e("div").append(
		{ [NODE]: document.createElement("div") }
	)
	```

### Views
[Views](views/index.md) are an abstraction for sequences of DOM nodes that may change over time. When views are used as content, they are owned by the element expression until the [lifecycle](lifecycle.md) during which the element was created is disposed.

=== "JSX"
	```jsx
	import { Show } from "rvx";

	<div>
		<Show when={someSignal}>
			{() => <>Hello World!</>}
		</Show>
	</div>
	```

=== "No Build"
	```jsx
	import { Show, e } from "./rvx.js";

	e("div").append(
		Show({
			when: someSignal,
			children: () => "Hello World!",
		})
	)
	```

Reusing view instances may result in undefined behavior. Consider using [`movable`](./views/movable.md) for safely reusing & moving arbitrary content.

### Arrays & Fragments
Content can be wrapped in arbitrarily nested arrays and JSX fragments.

=== "JSX"
	```jsx
	<div>
		<>
			{[
				"Hello World!",
				<div />,
			]}
		</>
	</div>
	```

	Note, that JSX fragments in rvx return their children as is. The return type of single-child or empty fragments may depend on your JSX transpiler.
	```jsx
	<></> // undefined
	<>42</> // 42
	<>foo{"bar"}</> // ["foo", "bar"]
	```

=== "No Build"
	```jsx
	e("div").append([
		[
			["Hello World!"],
			e("div"),
		],
	])
	```

## Namespaces
By default, elements are created as HTML elements. This works fine for most cases, but requires some extra work to create **SVG** or **MathML** elements.

The namespace URI for new elements can be [injected](context.md).

=== "JSX"
	```jsx
	import { Inject, XMLNS, SVG } from "rvx";

	<Inject context={XMLNS} value={SVG}>
		{() => <svg viewBox="0 0 100 100">...</svg>}
	</Inject>
	```

=== "No Build"
	```jsx
	import { XMLNS, SVG } from "./rvx.js";

	XMLNS.inject(SVG, () => {
		return e("svg").set("viewBox", "0 0 100 100").append(...)
	})
	```
