# Native-first

> Why the platform owns behavior first, which native features are relied on, and what "Svelte Lean owns nothing" means.

Page: https://svelte-lean.vercel.app/docs/architecture/native-first · Markdown: https://svelte-lean.vercel.app/docs/architecture/native-first.md · Index: https://svelte-lean.vercel.app/llms.txt

If HTML, CSS or the browser already provides a behavior, Svelte Lean uses it and owns nothing.

## The decision

- The platform comes first; a primitive is JavaScript only when the platform cannot provide the interaction (ADR 0001).
- 27 of the 50 primitives are native and ship no runtime: the package adds styles, contract types, documentation and development validation.
- The production fixture with button, dialog and popover markup emits a Svelte Lean chunk of 0 B.

Native before JavaScript. Every primitive declares its tier in its contract; the budgets are on [Runtime tiers](https://svelte-lean.vercel.app/docs/architecture/runtime-tiers.md).

## Platform features relied on

| Feature | Primitive | What the browser provides |
| --- | --- | --- |
| `<dialog> with command="show-modal" and command="close"` | Dialog | Top layer, page inertness, Escape, focus return to the invoker, the backdrop |
| `popover with popovertarget` | Popover, Menu | Top layer, light dismiss, one auto popover open at a time, aria-expanded, implicit anchor |
| `Invoker commands (command, commandfor)` | Dialog and Popover invokers | Open and close without a click handler |
| `<details> with name` | Disclosure | The open state, Enter and Space on the summary, exclusive groups |
| `Native form controls` | Button, Checkbox, Switch, Radio group | Focus, activation, checked state, arrow keys in a radio group, form participation |
| `CSS anchor positioning (position-area)` | Popover and Menu placement | Placement against the invoker, with fallbacks |
| `CSS state selectors (:open, :popover-open, :checked, :disabled, :focus-visible)` | Every stylesheet | State for styling without a mirrored attribute |

Baseline status and fallbacks: [Browser support](https://svelte-lean.vercel.app/docs/browser-support.md).

## Ownership

For a modal dialog:

| Svelte Lean owns | The browser owns |
| --- | --- |
| The stylesheet (`dialog.css`) | Open and close, through `showModal()` and the invoker commands |
| The contract: semantics, parts, keyboard, focus, SSR and JS-disabled behavior | The modal top layer, the backdrop and page inertness |
| Development validation of the markup | Dialog semantics, Escape, focus return, Tab staying inside |
| Types (`@svelte-lean/primitives/dialog`) | Form participation through `method="dialog"` |

Not in the package: focus trap, portal, z-index manager, scroll lock, positioning engine, `open` mirror ([Dialog](https://svelte-lean.vercel.app/primitives/dialog.md)).

## Examples

```svelte
<script lang="ts">
	// Nothing to import: the browser owns the dialog.
	// The styles are optional.
	import '@svelte-lean/styles/dialog.css';
</script>

<button type="button" data-slean="button" commandfor="settings"
	command="show-modal">Settings</button>

<dialog id="settings" data-slean="dialog" closedby="any"
	aria-labelledby="settings-title">
	<header>
		<h2 id="settings-title">Settings</h2>
		<p>Changes apply to this device.</p>
	</header>
	…
	<footer>
		<button type="button" data-slean="button" commandfor="settings"
			command="close">Close</button>
	</footer>
</dialog>
```

Press Escape: focus returns to the button. The interaction is the browser's.

```svelte
<script lang="ts">
	// Nothing to import: the Popover API owns the top layer and light dismiss.
	import '@svelte-lean/styles/popover.css';
</script>

<button type="button" popovertarget="account">Account</button>

<div id="account" popover data-slean="popover" data-slean-side="bottom" data-slean-align="start">
	<p>Signed in as Amara Okafor.</p>
</div>
```

Light dismiss, Escape and the top layer come from the Popover API; placement is CSS anchor positioning where supported.

## Consequences

- Each contract names the Baseline features it depends on and the fallback.
- Native primitives work before hydration and without client JavaScript (tested).
- Every primitive page opens with plain markup, never a wrapper component.
- Native semantics sometimes limit customization; see [Trade-offs](https://svelte-lean.vercel.app/docs/trade-offs.md).

## Revisit when

No Baseline feature meets a required behavior; the primitive then moves up a tier, with the reason in its contract.

## Source

- ADR 0001, Native before JavaScript
- Dialog contract and Popover contract
- native.spec.ts: the browser tests, including the runs with JavaScript disabled
- fixtures/native-only: the production build that asserts no behavior runtime
