# Ellipsis for Further Input

**SHOULD** · **ID:** `interactions-ellipsis-for-input` · **Category:** interactions
**Source:** [Vercel](https://github.com/vercel-labs/agent-skills/blob/main/skills/web-design-guidelines/SKILL.md)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/interactions-ellipsis-for-input

> SHOULD: Ellipsis (`…`) for options that open follow-ups (eg, "Rename…") and loading states (eg, "Loading…", "Saving…", "Generating…")

Menu options that open follow-ups end with ellipsis

An ellipsis (…) signals that more input or time is needed. Use it for menu items that open dialogs ("Rename…", "Delete…") and for processing states ("Saving…", "Loading…"). Don't use it for direct actions that complete immediately.

## Bad — do not do this

`interactions-ellipsis-for-input-bad`

```tsx
import { useState } from 'react';

const itemClass =
  'w-full text-left px-3 py-2 bg-card rounded text-sm border border-border transition-colors hover:bg-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring';

export function EllipsisForInputBad() {
  const [saving, setSaving] = useState(false);

  const save = () => {
    setSaving(true);
    setTimeout(() => setSaving(false), 1500);
  };

  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="space-y-2 bg-muted rounded-lg p-4">
        <p className="text-xs text-muted-foreground">Menu</p>
        <button className={itemClass}>Open</button>
        <button className={itemClass}>Rename</button>
        <button className={itemClass}>Delete</button>
      </div>

      <div className="space-y-2">
        <p className="text-xs text-muted-foreground">Processing state (click it)</p>
        <button
          onClick={save}
          disabled={saving}
          className="px-4 py-2 bg-primary text-primary-foreground rounded-lg text-sm transition-colors duration-150 ease-out hover:bg-primary/90 disabled:opacity-70"
        >
          Save
        </button>
      </div>

      <p className="text-xs text-destructive">
        Nothing signals which actions open a follow-up, and the button still reads <code>Save</code> while it is
        saving, so there is no cue that work is in flight
      </p>
    </div>
  );
}
```

## Good — do this

`interactions-ellipsis-for-input-good`

```tsx
import { useState } from 'react';

const itemClass =
  'w-full text-left px-3 py-2 bg-card rounded text-sm border border-border transition-colors hover:bg-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring';

export function EllipsisForInputGood() {
  const [saving, setSaving] = useState(false);

  const save = () => {
    setSaving(true);
    setTimeout(() => setSaving(false), 1500);
  };

  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="space-y-2 bg-muted rounded-lg p-4">
        <p className="text-xs text-muted-foreground">Menu</p>
        <button className={itemClass}>Open</button>
        <button className={itemClass}>Rename…</button>
        <button className={itemClass}>Delete…</button>
      </div>

      <div className="space-y-2">
        <p className="text-xs text-muted-foreground">Processing state (click it)</p>
        <button
          onClick={save}
          disabled={saving}
          className="px-4 py-2 bg-primary text-primary-foreground rounded-lg text-sm transition-colors duration-150 ease-out hover:bg-primary/90 disabled:opacity-70"
        >
          {saving ? 'Saving…' : 'Save'}
        </button>
      </div>

      <p className="text-xs text-success">
        Both halves of the rule: menu items that open a follow-up (<code>Rename…</code>) and processing states
        (<code>Saving…</code>) take an ellipsis. A direct action like <code>Open</code> does not.
      </p>
    </div>
  );
}
```

## References

- [Ellipsis in UI](https://en.wikipedia.org/wiki/Ellipsis)
