---
title: raw()
---

# raw()

Marks a string as **trusted**: every check is turned off for it.

## Signature

```tsx
raw(value: string): RawString
```

## Usage

Use it for HTML from a trusted source (a Markdown renderer, a sanitizer, your
own templates), never for user input:

```tsx
import { raw } from "@vincle/core";

<div>{raw(await renderMarkdown(post.body))}</div>;
<div>{raw(DOMPurify.sanitize(userInput))}</div>;

// ❌ XSS if userInput contains <script>alert(1)</script>
<div>{raw(userInput)}</div>;
// ✅ Vincle escapes by default
<div>{userInput}</div>;
```

## In an attribute

In an attribute, `raw()` is a trusted _value_, not markup: it is emitted as
written, a URL included (no scheme check), except `"`, so it can never end its
attribute. The escaped `"` decodes back before CSS, JS or the DOM reads it, so
the value still means what it says.

```tsx
<a href={raw("javascript:go()")}>x</a>; // href="javascript:go()"
<a title={raw('" onmouseover="alert(1)')}>x</a>; // title="&quot; onmouseover=&quot;…"
```

A sanitizer's output is markup: it belongs in content, not in an attribute.

## dangerouslySetInnerHTML

The same promise as `raw()`, for React compatibility:

```tsx
<div dangerouslySetInnerHTML={{ __html: "<b>bold</b>" }} />
```

## `rawUrl()`: a narrower trust boundary

`rawUrl()` is a separate function for URLs. It skips only the scheme check: the
value is still escaped, so unlike `raw()` it cannot end its attribute, and in
content position it is text like any other.

```tsx
import { rawUrl } from "@vincle/core";

<a href={rawUrl("phpstorm://open?file=src/app.ts")}>open in the IDE</a>;
```

### `raw()` vs `rawUrl()`

| Function   | In content                 | In attribute                         | Grep target |
| ---------- | -------------------------- | ------------------------------------ | ----------- |
| `raw()`    | Emitted as verbatim markup | Escaped as a value, trust for scheme | `raw(`      |
| `rawUrl()` | N/A (type error)           | Trust for scheme only, still escaped | `rawUrl(`   |

A `RawString` is **markup** — it bypasses escaping entirely. A `RawUrl` is a
**URL** — it bypasses only the scheme filter. The distinction is enforced at
both the type level (`RawString` and `RawUrl` are nominally distinct) and
runtime (`instanceof` checks treat them differently). An audit should list
every `raw()` call and verify the value originates from a trusted source
(sanitizer output, template engine, hardcoded markup), never from user input.

## See also

- [Security model](/guide/security): full XSS defence model
- [VNode](/api/core/jsx-types): `RawString` in the type union
