Returnless UI

Action field

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.

Props
label?:
string | null
Defaults to null
The label for the input field.
labelFor?:
string | null
Defaults to null
The id of the input field.
error?:
string | null
Defaults to null
The error message for the input field.
helpText?:
string | null
Defaults to null
The helper text for the input field.

Usage

Use an action field when you want the user to type a short value and immediately trigger one clear action.

Default

A basic action field with helper text and the button on the right.

js
<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>

Button on the start

Move the action button to the left when a verb-first pattern makes sense (for example, Search).

js
<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>

With label

Show a visible label above the input field.

js
<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>

With error

Show an inline error message and highlight the field when the input is invalid.

Enter a valid email address

Type a keyword and press the button

js
<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>

Disabled field

Disables both the input and the built-in button, preventing any interaction.

js
<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>

Button disabled only

Leaves the input active but disables the action button. Useful when input is allowed but the action cannot yet be performed.

js
<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>

Best practices

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:

    • End (right) — default, when users type then submit.
    • Start (left) — when an action verb should come first (e.g. Search).

Content guidelines

Labels

  • Use clear, concise nouns or short phrases.
  • Start with a capital letter and avoid ending punctuation.
  • Use hide-label when a visible label isn’t needed but the field still requires an accessible name.

Button text

  • Use short, clear verbs like Apply, Search, or Send.
  • Avoid vague terms like Go or Do it.

Accessibility

Action fields use semantic <label>, <input>, and <button> elements.

  • The required label prop provides an accessible name. Use hide-label to visually hide it.
  • helpText and error are associated with the input via aria-describedby.
  • Use disabled to set the HTML disabled attribute on the input and the button together.
  • Use button-disabled to disable only the button while keeping the input active.
  • The entire group shows a single focus ring when any of its internal elements receive focus.