Link
The Link field captures URLs as either a plain string or a structured object with optional label and target values.
Plain URL Mode
Plain mode is the default. The submitted value is a string:
use InertiaUI\Forms\Fields\Link;
Link::make('url');Submitted value:
"https://example.test"A bound model containing an object or array in plain mode makes the PHP field read its url key. Calling plain() also turns off withLabel() and withTarget().
Structured Mode
Use withLabel() or withTarget() when the saved value should include link metadata:
Link::make('cta')
->withLabel()
->withTarget();Submitted value:
{
"url": "https://example.test",
"label": "Read the guide",
"target": "_blank"
}You may opt into structured mode without label or target controls:
Link::make('source')->structured();Structured values always contain a string url. The optional label and target keys are included only when their controls are enabled. A bound string is normalized to { "url": "..." }; missing or null values become empty strings for the enabled keys.
URL Schemes
By default, users may enter URLs without a scheme, such as example.test/docs. Present schemes must be allowed.
Link::make('url')->requireScheme();Restrict the allowed schemes:
Link::make('url')->allowedSchemes(['https']);
Link::make('callback')->allowedSchemes('https', 'web+docs');The default allowed schemes are http and https. allowedSchemes() accepts an array or variadic strings. Values are lowercased, surrounding :/ is removed, duplicates are discarded, and an empty or invalid scheme list is rejected. Without requireScheme(), a value without a scheme is still accepted; any scheme that is present must be allowed.
Validation
Plain mode adds string plus the package URL rule. Structured mode adds an array rule and validates the nested url, label, and target paths.
Link::make('cta')
->withLabel()
->withTarget()
->requireScheme()
->required();This validates cta.url as required and checks that cta.target is empty or one of _self, _blank, _parent, or _top. Without top-level required(), the nested URL is nullable. Enabled labels are nullable strings.
The Link-specific methods above compose with shared field APIs. Use Form Class for labels, help text, and placeholders, Model Binding for default(), Validation for rules, required fields, and precognition, Styling for classes and presentation helpers, Conditional Visibility, and Authorization.
Using the Component Directly
You may render Link outside the generated <Form> by passing serialized form.getField(...) props or local state.
<script setup lang="ts">
import type { LinkValue } from '@inertiaui/form-vue'
import { Link } from '@inertiaui/form-vue/components'
import { ref } from 'vue'
const cta = ref<LinkValue>({
url: 'https://example.test/docs',
label: 'Read the guide',
target: '_blank',
})
const isArchived = false
const isLocked = false
const hideLabel = false
const trackBlur = () => {}
</script>
<template>
<Link
v-model="cta"
id="marketing-link"
name="cta"
label="Call to action"
help="Use an HTTPS URL for public campaign links."
placeholder="https://example.test/docs"
mode="structured"
:require-scheme="true"
:allowed-schemes="['https']"
:with-label="true"
:with-target="true"
required
precognitive
:disabled="isArchived"
:readonly="isLocked"
:label-sr-only="hideLabel"
badge="Public"
badge-class="bg-zinc-100 text-zinc-700"
label-trailing="Optional"
label-trailing-class="text-zinc-500"
tooltip="Shown wherever this campaign is linked."
help-position="below"
layout="split"
control-position="end"
label-class="font-medium"
help-class="text-zinc-500"
error-class="text-red-600"
wrapper-class="max-w-3xl"
control-class="bg-white"
class="font-medium"
invalid
error="Enter a secure HTTPS URL."
data-testid="marketing-link"
aria-label="Campaign URL"
@blur="trackBlur"
/>
</template>import { useState } from 'react'
import type { LinkValue } from '@inertiaui/form-react'
import { Link } from '@inertiaui/form-react/components'
export function CallToAction() {
const [cta, setCta] = useState<LinkValue>({
url: 'https://example.test/docs',
label: 'Read the guide',
target: '_blank',
})
const isArchived = false
const isLocked = false
const hideLabel = false
const trackBlur = () => {}
return (
<Link
value={cta}
onValueChange={setCta}
id="marketing-link"
name="cta"
label="Call to action"
help="Use an HTTPS URL for public campaign links."
placeholder="https://example.test/docs"
mode="structured"
requireScheme
allowedSchemes={['https']}
withLabel
withTarget
required
precognitive
disabled={isArchived}
readonly={isLocked}
labelSrOnly={hideLabel}
badge="Public"
badgeClass="bg-zinc-100 text-zinc-700"
labelTrailing="Optional"
labelTrailingClass="text-zinc-500"
tooltip="Shown wherever this campaign is linked."
helpPosition="below"
layout="split"
controlPosition="end"
labelClass="font-medium"
helpClass="text-zinc-500"
errorClass="text-red-600"
wrapperClass="max-w-3xl"
controlClass="bg-white"
class="font-medium"
invalid
error="Enter a secure HTTPS URL."
data-testid="marketing-link"
aria-label="Campaign URL"
onBlur={trackBlur}
/>
)
}Vue uses v-model. React uses controlled value plus onValueChange. Native attributes and listeners target the URL input; see Native Attributes And Events.