The Action field combines a single-line text input with a connected button.
It’s designed for quick, single-step tasks such as applying a discount code, sending an invite, or running a search.
Use an action field when you want the user to type a short value and immediately trigger one clear action.
A basic action field with helper text and the button on the right.
<script lang="ts" setup>
import { ref } from 'vue';
import { ActionField } from '@returnless/focus-ui';
const promo = ref('');
</script>
<template>
<ActionField>
<TextFieldInput
v-model="promo"
name="promo"
id="promo"
placeholder="Enter code"
/>
<Button
variant="outline"
@click="showAlert(promo)"
>
Apply
</Button>
</ActionField>
</template>Move the action button to the left when a verb-first pattern makes sense (for example, Search).
<script lang="ts" setup>
import { ref } from 'vue';
import { ActionField } from '@returnless/focus-ui';
const search = ref('');
</script>
<template>
<ActionField>
<Button
label="Search"
variant="outline"
@click="showAlert(search)"
>
Search
</Button>
<TextFieldInput
v-model="search"
name="search"
placeholder="Search products"
/>
</ActionField>
</template>Show a visible label above the input field.
<script lang="ts" setup>
import { ref } from 'vue';
import { ActionField } from '@returnless/focus-ui';
const withError = ref('');
</script>
<template>
<ActionField label="Invite email" label-for="invite">
<TextFieldInput
v-model="withError"
id="invite"
name="invite"
placeholder="name@example.com"
/>
<Button
label="Send"
variant="outline"
@click="showAlert(withError)"
>
Send
</Button>
</ActionField>
</template>Show an inline error message and highlight the field when the input is invalid.
Type a keyword and press the button
<script lang="ts" setup>
import { ref } from 'vue';
import { ActionField } from '@returnless/focus-ui';
const withError = ref('');
</script>
<template>
<ActionField
error="Enter a valid email address"
help-text="Type a keyword and press the button"
>
<TextFieldInput
v-model="withError"
name="invite"
error="Enter a valid email address"
placeholder="name@example.com"
/>
<Button
label="Send"
variant="outline"
@click="showAlert(withError)"
>
Send
</Button>
</ActionField>
</template>Disables both the input and the built-in button, preventing any interaction.
<script lang="ts" setup>
import { ref } from 'vue';
import { ActionField } from '@returnless/focus-ui';
const fieldDisabled = ref('');
</script>
<template>
<ActionField>
<TextFieldInput
v-model="fieldDisabled"
name="field-disabled"
placeholder="Placeholder text"
disabled
/>
<Button
label="Button"
variant="outline"
@click="showAlert(fieldDisabled)"
>
Button
</Button>
</ActionField>
</template>Leaves the input active but disables the action button. Useful when input is allowed but the action cannot yet be performed.
<script lang="ts" setup>
import { ref } from 'vue';
import { ActionField } from '@returnless/focus-ui';
const buttonDisabled = ref('');
</script>
<template>
<ActionField>
<TextFieldInput
v-model="buttonDisabled"
name="button-disabled"
placeholder="Placeholder text"
/>
<Button
label="Button"
variant="outline"
disabled
@click="showAlert(buttonDisabled)"
>
Button
</Button>
</ActionField>
</template>Action fields should:
Be clearly labeled so users know what value to enter.
Keep the button label short and action-oriented.
Provide helper text for context and show concise error messages when input is invalid.
Place the button:
hide-label when a visible label isn’t needed but the field still requires an accessible name.Action fields use semantic <label>, <input>, and <button> elements.
label prop provides an accessible name. Use hide-label to visually hide it.helpText and error are associated with the input via aria-describedby.disabled to set the HTML disabled attribute on the input and the button together.button-disabled to disable only the button while keeping the input active.