Hold Button <mv-hold-button>

Bouton « Maintenir pour confirmer » pour les actions destructrices : tant qu’il est pressé, un liquide monte à l’intérieur (ou arrive par le côté) et inverse le libellé là où il le recouvre, relâcher trop tôt le fait redescendre, et un maintien complet se conclut par une coche, un libellé de fin et mv-confirm.

CatégorieMicro-interactions
TypeWeb Component (<mv-hold-button>)
Statutstable
Keywordshold, long-press, confirm, destructive, delete, progress, safety, liquid

When to use

  • A destructive action such as deleting an account or project should require a deliberate press and hold
  • An important but non-destructive action should be protected from accidental clicks with an accent hold gauge

Avoid when

  • The user must read consequences or type a confirmation before proceeding → use Dialog instead
  • The action stops a long-running process and users should see what they keep before stopping → use Salvage Stop instead
  • The action is frequent and harmless; forcing a hold slows users down for no benefit → use Button instead

Installation

node scripts/add.mjs hold-button --out ./src/marvelous

Agent IA avec le serveur MCP de Marvelous UI : install_components({ slugs: ["hold-button"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Fichiers copiés (dépendances comprises) : tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, components/hold-button/hold-button.js, components/hold-button/hold-button.css.

Utilisation

Démarrage rapide, le balisage minimal qui fonctionne :

<mv-hold-button done-label="Project deleted">Hold to delete</mv-hold-button>

Balisage de référence : partez de celui-ci et personnalisez-le avec les attributs, data-* et les variables CSS :

<div style="display:grid;gap:1.25rem;width:100%;max-width:440px">
  <div style="display:grid;gap:.9rem;padding:1.1rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:var(--mv-surface)">
    <div style="display:grid;gap:.25rem">
      <strong style="font-size:.95rem">Delete “Lumen website redesign”</strong>
      <span style="font-size:.82rem;color:var(--mv-fg-muted)">All 48 files and their history will be permanently deleted.</span>
    </div>
    <div style="display:flex;gap:.6rem;align-items:center;flex-wrap:wrap">
      <mv-hold-button duration="1600" done-label="Project deleted" id="hb-demo-delete">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M10 11v6M14 11v6M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-12M9 7V4h6v3"/></svg>
        Hold to delete
      </mv-hold-button>
      <span id="hb-demo-log" style="font-size:.8rem;color:var(--mv-fg-subtle)">Let go early to cancel.</span>
    </div>
  </div>
  <div style="display:flex;gap:.75rem;align-items:center;justify-content:center;flex-wrap:wrap">
    <mv-hold-button data-variant="accent" data-fill="sweep" duration="1000" done-label="Published" style="--mv-hold-button-radius:var(--mv-radius-full)">Hold to publish</mv-hold-button>
  </div>
</div>
<script type="module">
  const el = document.getElementById("hb-demo-delete");
  el?.addEventListener("mv-confirm", () => {
    const log = document.getElementById("hb-demo-log");
    if (log) log.textContent = "mv-confirm received at " + new Date().toLocaleTimeString("en-US");
  });
</script>

API

Attributes

NameTypeDefaultDescription
durationnumber1500Required hold time (ms).
done-labelstringConfirmedLabel (and announcement) once confirmed.
hintstringPress and hold to confirmInstruction: accessible description, and the bubble shown after a tap that did not hold.
resetnumber2400Return to the initial state after confirmation (ms, 0 = stays confirmed).
disabledbooleanDisables the button.
data-variantaccent(danger)Accent color instead of danger (non-destructive actions).
data-fillsweep(rise)The liquid fills from the start edge instead of rising from the bottom.
data-stateidle | holding | rewinding | armed | doneSet by the component.

Properties

NameTypeDescription
progressnumberProgress 0..1 (read-only).
strings{ hint?, done?, again? }Overrides for the default texts (translation). The hint and done-label attributes win; again = "Press again to confirm".

Methods

NameDescription
resetState({ instant })Returns to the initial state (rewinds, or instantly).

Events

NameDescription
mv-confirmThe hold went all the way.

Content structure

NameDescription
(content)Label, SVG icon included.

CSS variables

NameDefaultDescription
--mv-hold-button-colorvar(--mv-danger)Fill and text color.
--mv-hold-button-fgwhiteText on the fill.
--mv-hold-button-radiusvar(--mv-radius-md)Radius.

Accessibility

A real <button> described by the instruction (aria-describedby). Keyboard: hold Space or Enter (key repeat is ignored, releasing drains the liquid, Escape or losing focus cancels). A tap never confirms: it shows the instruction and nudges the button. A click with no press behind it (screen readers, switch access) arms the button (“Press again to confirm”, announced, 5 s) and a second one confirms, so the action never depends on a timed gesture alone. Confirmation is announced by a role=status region and the button becomes aria-disabled while confirmed. Touch: no context menu during the press, scrolling cancels, a short vibration on completion where supported. Reduced motion: the level stays (it carries information), the rolling surface, the nudge and the slides go away. Forced colors: the liquid is drawn in Highlight with HighlightText on it.

Cette page a été traduite par IA. Signaler un problème de traduction