{salutation}, {name}!
; +} +``` + +Use it in a route or another component: + +```tsx +--- +import Greeting from '../components/Greeting.tsx'; +--- + +This is the card body.
+Are you sure you want to delete this item?
+Current time: {time}
; +} +``` + +## Lifecycle Hooks + +Client-side components can use the following lifecycle hooks: + +| Hook | When it runs | +|------|-------------| +| `onMount(fn)` | After the component is first rendered and inserted into the DOM | +| `onUpdate(fn)` | After every re-render (reactive signal change) | +| `onCleanup(fn)` | Before the component unmounts or before the next `onUpdate` call | +| `onDestroy(fn)` | When the component is permanently unmounted | + +```tsx +import { signal, onMount, onUpdate, onCleanup } from 'velox/client'; + +export default function DataComponent() { + const data = signalLoading...
:Error: {error.message}
; + + return ( +{t('home.hero.subtitle')}
+ {t('home.cta')} +{t('post.publishedOn', { date: publishedDate })}
+``` + +### Pluralisation + +Velox uses the ICU message format for pluralisation: + +```typescript +t('post.comments', { count: 0 }); // "No comments" +t('post.comments', { count: 1 }); // "1 comment" +t('post.comments', { count: 42 }); // "42 comments" +``` + +### In Client Components + +```typescript +import { useTranslations } from 'velox/i18n/client'; + +export default function LikeButton({ postId }: { postId: string }) { + const t = useTranslations(); + const liked = signal(false); + + return ( + + ); +} +``` + +## Locale Routing + +With `routing: 'prefix-except-default'` and `defaultLocale: 'en'`: + +| URL | Locale | +|-----|--------| +| `/` | `en` | +| `/about` | `en` | +| `/fr` | `fr` | +| `/fr/about` | `fr` | +| `/de/blog/my-post` | `de` | + +Velox automatically generates alternate hreflang links for SEO. + +## Locale Switcher Component + +```tsx +import { useLocale, usePathname } from 'velox/i18n/client'; + +export default function LocaleSwitcher() { + const { locale, locales } = useLocale(); + const pathname = usePathname(); + + return ( +Edit routes/index.velox to get started.
Send us a message at hello@example.com
+Todo from API: {todo.title}
+Count: {count.value}
+ +{count.value}
+{count}
+``` + +The second form (`{count}` without `.value`) subscribes the DOM node directly to the signal. This is more efficient because Velox skips the component function entirely and updates only the text node when the signal changes. + +## Computed Signals + +A computed signal derives its value from one or more other signals. It re-evaluates automatically when its dependencies change: + +```typescript +import { signal, computed } from 'velox/client'; + +const firstName = signal('Jane'); +const lastName = signal('Doe'); +const fullName = computed(() => `${firstName.value} ${lastName.value}`); + +console.log(fullName.value); // "Jane Doe" +firstName.value = 'John'; +console.log(fullName.value); // "John Doe" +``` + +Computed signals are lazy and memoised — the computation only runs when the value is read, and only re-runs if a dependency has changed since the last read. + +## Effects + +An effect runs a side effect whenever its reactive dependencies change: + +```typescript +import { signal, effect } from 'velox/client'; + +const query = signal(''); + +effect(() => { + console.log('Search query changed:', query.value); + // this re-runs every time query.value changes +}); +``` + +Effects clean themselves up automatically when the component unmounts. To clean up manually within an effect (e.g., cancel a previous request): + +```typescript +effect(() => { + const controller = new AbortController(); + fetch(`/api/search?q=${query.value}`, { signal: controller.signal }) + .then(r => r.json()) + .then(results => resultsSignal.value = results); + + return () => controller.abort(); // cleanup function +}); +``` + +## Stores + +For shared state across components, define a store. A store is a module that encapsulates signals and exposes a clean interface: + +```typescript +// lib/stores/cart.ts +import { signal, computed } from 'velox/client'; + +export interface CartItem { + id: string; + name: string; + price: number; + quantity: number; +} + +const items = signalHello, {userProfile.value.data.name}
+ )} + {userProfile.value.status === 'error' && ( +Error: {userProfile.value.error.message}
+ )} +{salutation}, {name}!
;\n}\n```\n\nUse it in a route or another component:\n\n```tsx\n---\nimport Greeting from '../components/Greeting.tsx';\n---\n\nThis is the card body.
\nAre you sure you want to delete this item?
\nCurrent time: {time}
;\n}\n```\n\n## Lifecycle Hooks\n\nClient-side components can use the following lifecycle hooks:\n\n| Hook | When it runs |\n|------|-------------|\n| `onMount(fn)` | After the component is first rendered and inserted into the DOM |\n| `onUpdate(fn)` | After every re-render (reactive signal change) |\n| `onCleanup(fn)` | Before the component unmounts or before the next `onUpdate` call |\n| `onDestroy(fn)` | When the component is permanently unmounted |\n\n```tsx\nimport { signal, onMount, onUpdate, onCleanup } from 'velox/client';\n\nexport default function DataComponent() {\n const data = signalLoading...
:{t('home.hero.subtitle')}
\n {t('home.cta')}\n{t('post.publishedOn', { date: publishedDate })}
\n```\n\n### Pluralisation\n\nVelox uses the ICU message format for pluralisation:\n\n```typescript\nt('post.comments', { count: 0 }); // \"No comments\"\nt('post.comments', { count: 1 }); // \"1 comment\"\nt('post.comments', { count: 42 }); // \"42 comments\"\n```\n\n### In Client Components\n\n```typescript\nimport { useTranslations } from 'velox/i18n/client';\n\nexport default function LikeButton({ postId }: { postId: string }) {\n const t = useTranslations();\n const liked = signal(false);\n\n return (\n \n );\n}\n```\n\n## Locale Routing\n\nWith `routing: 'prefix-except-default'` and `defaultLocale: 'en'`:\n\n| URL | Locale |\n|-----|--------|\n| `/` | `en` |\n| `/about` | `en` |\n| `/fr` | `fr` |\n| `/fr/about` | `fr` |\n| `/de/blog/my-post` | `de` |\n\nVelox automatically generates alternate hreflang links for SEO.\n\n## Locale Switcher Component\n\n```tsx\nimport { useLocale, usePathname } from 'velox/i18n/client';\n\nexport default function LocaleSwitcher() {\n const { locale, locales } = useLocale();\n const pathname = usePathname();\n\n return (\nEdit routes/index.velox to get started.
Send us a message at hello@example.com
\nTodo from API: {todo.title}
\nCount: {count.value}
\n \n{count.value}
\n{count}
\n```\n\nThe second form (`{count}` without `.value`) subscribes the DOM node directly to the signal. This is more efficient because Velox skips the component function entirely and updates only the text node when the signal changes.\n\n## Computed Signals\n\nA computed signal derives its value from one or more other signals. It re-evaluates automatically when its dependencies change:\n\n```typescript\nimport { signal, computed } from 'velox/client';\n\nconst firstName = signal('Jane');\nconst lastName = signal('Doe');\nconst fullName = computed(() => `${firstName.value} ${lastName.value}`);\n\nconsole.log(fullName.value); // \"Jane Doe\"\nfirstName.value = 'John';\nconsole.log(fullName.value); // \"John Doe\"\n```\n\nComputed signals are lazy and memoised \u2014 the computation only runs when the value is read, and only re-runs if a dependency has changed since the last read.\n\n## Effects\n\nAn effect runs a side effect whenever its reactive dependencies change:\n\n```typescript\nimport { signal, effect } from 'velox/client';\n\nconst query = signal('');\n\neffect(() => {\n console.log('Search query changed:', query.value);\n // this re-runs every time query.value changes\n});\n```\n\nEffects clean themselves up automatically when the component unmounts. To clean up manually within an effect (e.g., cancel a previous request):\n\n```typescript\neffect(() => {\n const controller = new AbortController();\n fetch(`/api/search?q=${query.value}`, { signal: controller.signal })\n .then(r => r.json())\n .then(results => resultsSignal.value = results);\n\n return () => controller.abort(); // cleanup function\n});\n```\n\n## Stores\n\nFor shared state across components, define a store. A store is a module that encapsulates signals and exposes a clean interface:\n\n```typescript\n// lib/stores/cart.ts\nimport { signal, computed } from 'velox/client';\n\nexport interface CartItem {\n id: string;\n name: string;\n price: number;\n quantity: number;\n}\n\nconst items = signalHello, {userProfile.value.data.name}
\n )}\n {userProfile.value.status === 'error' && (\nError: {userProfile.value.error.message}
\n )}\n