Skip to content
Open
Show file tree
Hide file tree
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
8 changes: 8 additions & 0 deletions website/docs/usage_with_frameworks/svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@ sidebar_position: 3
title: Svelte
---

import SvelteIntegrationSandpack from '@site/src/components/Sandpack/SvelteIntegration';

# Using Vest with Svelte

Vest integrates naturally with Svelte's reactive stores and reactive statements, providing elegant validation for your forms.

## Interactive Example

Edit this Svelte form to see how Vest's validation suite responds in real time.

<SvelteIntegrationSandpack />

## Quick Start

````svelte
Expand Down
8 changes: 8 additions & 0 deletions website/docs/usage_with_frameworks/vue.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@ sidebar_position: 2
title: Vue
---

import VueIntegrationSandpack from '@site/src/components/Sandpack/VueIntegration';

# Using Vest with Vue

Vest integrates beautifully with Vue 3's Composition API and reactivity system, providing declarative validation for your forms.

## Interactive Example

Explore a live Vue 3 form wired to a Vest suite. Edit the component or the suite to see validation updates instantly.

<VueIntegrationSandpack />

## Quick Start with Composition API

```vue
Expand Down
196 changes: 196 additions & 0 deletions website/src/components/Sandpack/SvelteIntegration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import React from 'react';
import Sandpack from './index';
import commonStyles from '../RawExample.module.css';

const AppCode = `<script>
import { create, test, enforce } from "vest";
import "./styles.css";

const suite = create((data = {}) => {
test("username", "Username is required", () => {
enforce(data.username).isNotBlank();
});

test("username", "Username must be at least 3 characters", () => {
enforce(data.username).longerThanOrEquals(3);
});

test("email", "Email is required", () => {
enforce(data.email).isNotBlank();
});

test("email", "Please enter a valid email", () => {
enforce(data.email).isEmail();
});
});

let form = {
username: "",
email: "",
};

let result = suite.get();

const updateField = (fieldName, value) => {
form = { ...form, [fieldName]: value };

suite
.afterEach((res) => {
result = res;
})
.run(form, fieldName);
};

const handleSubmit = () => {
suite
.afterEach((res) => {
result = res;

if (!res.hasErrors()) {
alert("Form is valid! 🎉");
}
})
.run(form);
};
</script>

<main class="app">
<h1>Vest + Svelte</h1>
<form on:submit|preventDefault={handleSubmit}>
<label>
Username
<input
value={form.username}
on:input={(event) => updateField('username', event.target.value)}
placeholder="Ada Lovelace"
/>
{#if result.hasErrors('username')}
<span class="error">{result.getErrors('username')[0]}</span>
{/if}
</label>

<label>
Email
<input
type="email"
value={form.email}
on:input={(event) => updateField('email', event.target.value)}
placeholder="[email protected]"
/>
{#if result.hasErrors('email')}
<span class="error">{result.getErrors('email')[0]}</span>
{/if}
</label>

<button type="submit">Validate</button>
</form>

<section class="status" aria-live="polite">
Form is {result.isValid() ? 'valid ✅' : 'not valid yet'}
</section>
</main>
`;

const StylesCode = `:root {
color-scheme: dark;
font-family: "Inter", system-ui, -apple-system, sans-serif;
background: #0f1115;
color: #f8fafc;
}

body {
margin: 0;
}

.app {
max-width: 720px;
margin: 0 auto;
padding: 32px 24px 48px;
}

h1 {
margin: 0 0 16px;
font-size: 1.6rem;
}

form {
display: grid;
gap: 16px;
}

label {
display: grid;
gap: 6px;
font-size: 0.95rem;
color: #cbd5e1;
}

input {
padding: 10px 12px;
border-radius: 8px;
border: 1px solid #1f2933;
background: #0c0e13;
color: #fff;
}

input:focus {
outline: none;
border-color: #7c3aed;
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.25);
}

button {
padding: 12px 14px;
border-radius: 10px;
border: none;
background: #7c3aed;
color: white;
font-weight: 600;
cursor: pointer;
transition: transform 120ms ease, box-shadow 120ms ease;
}

button:hover {
transform: translateY(-1px);
box-shadow: 0 8px 30px rgba(124, 58, 237, 0.35);
}

.error {
color: #fb7185;
font-size: 0.85rem;
}

.status {
margin-top: 22px;
padding: 14px 12px;
border: 1px solid #1f2933;
border-radius: 10px;
background: #0c0e13;
color: #cbd5e1;
}
`;

export default function SvelteIntegrationSandpack() {
return (
<div className={commonStyles.codeWindow}>
<Sandpack
template="svelte"
theme="dark"
files={{
'/App.svelte': AppCode,
'/styles.css': StylesCode,
}}
customSetup={{
dependencies: {
vest: 'next',
},
}}
options={{
activeFile: '/App.svelte',
visibleFiles: ['/App.svelte'],
editorHeight: 700,
}}
/>
</div>
);
}
Loading
Loading