diff --git a/ivette/src/dome/renderer/layout/forms.tsx b/ivette/src/dome/renderer/layout/forms.tsx
index b40f4ae2d36fa5ffd11e9a9bb4c7118d1df691e3..621ff83af522ab9ae1d13ac623ed0642753ecd44 100644
--- a/ivette/src/dome/renderer/layout/forms.tsx
+++ b/ivette/src/dome/renderer/layout/forms.tsx
@@ -39,6 +39,7 @@
  */
 
 import { debounce } from 'lodash';
+import Events from 'events';
 import React from 'react';
 import * as Dome from 'dome';
 import * as Utils from 'dome/misc/utils';
@@ -50,8 +51,15 @@ export type FieldError =
   | undefined | boolean | string
   | { [key: string]: FieldError } | FieldError[];
 export type Checker<A> = (value: A) => boolean | FieldError;
-export type Callback<A> = (value: A, error: FieldError) => void;
-export type FieldState<A> = [A, FieldError, Callback<A>];
+export type Callback<A> =
+  (value: A, error: FieldError, reset: boolean) => void;
+
+export interface FieldState<A> {
+  value: A;
+  error?: FieldError;
+  reset?: A;
+  onChanged: Callback<A>;
+}
 
 /* --------------------------------------------------------------------------*/
 /* --- State Errors Utilities                                             ---*/
@@ -107,6 +115,113 @@ function isValidArray(err: FieldError[]): boolean {
   return true;
 }
 
+/* --------------------------------------------------------------------------*/
+/* --- Reset Hooks                                                        ---*/
+/* --------------------------------------------------------------------------*/
+
+export type ResetCallback = () => void;
+
+/**
+   Controller for _buffered_ field states.
+ */
+export class BufferController {
+  private readonly evt = new Events();
+
+  /** Notify all reset listener events. */
+  reset(): void { this.evt.emit('reset'); }
+
+  /** Notify all commit listener events. */
+  commit(): void { this.evt.emit('commit'); }
+
+  /** There are active listeners for Reset event. */
+  hasReset(): boolean { return this.evt.listenerCount('reset') > 0; }
+
+  /** There are active listeners for Commit event. */
+  hasCommit(): boolean { return this.evt.listenerCount('commit') > 0; }
+
+  /** @internal */
+  onReset(fn: ResetCallback): void { this.evt.addListener('reset', fn); }
+
+  /** @internal */
+  offReset(fn: ResetCallback): void { this.evt.addListener('reset', fn); }
+
+  /** @internal */
+  onCommit(fn: ResetCallback): void { this.evt.addListener('commit', fn); }
+
+  /** @internal */
+  offCommit(fn: ResetCallback): void { this.evt.addListener('commit', fn); }
+
+}
+
+/**
+   Insert a temporary buffer to stack modifications. Values are imported from
+   the input state, and modifications are stacked into an internal buffer.
+
+   The buffered state will perform the following actions
+   upon remote control events:
+
+   - on Reset event, the buffered state is restored to the input value.
+
+   - on Commit event, the buffered state is sent to the input callback.
+
+   The returned field state reflects the internal buffer state. Its local
+   reset value is either the input reset value or the current input value.
+
+ */
+export function useBuffer<A>(
+  remote : BufferController,
+  state: FieldState<A>
+): FieldState<A>
+{
+  const { value, error, reset, onChanged } = state;
+  const [ modified, setModified ] = React.useState(false);
+  const [ buffer, setBuffer ] = React.useState<A>(value);
+  const [ berror, setBerror ] = React.useState<FieldError>(error);
+  const staged = modified && !berror;
+
+  // --- Reset
+  React.useEffect(() => {
+    if (modified) {
+      const doReset = (): void => {
+        setModified(false);
+        setBuffer(value);
+        setBerror(error);
+      };
+      remote.onReset(doReset);
+      return () => remote.offReset(doReset);
+    } else return;
+  }, [remote, modified, value, error]);
+
+  // --- Commit
+  React.useEffect(() => {
+    if (staged) {
+      const doCommit = (): void => {
+        setModified(false);
+        onChanged(buffer, undefined, false);
+      };
+      remote.onCommit(doCommit);
+      return () => remote.offCommit(doCommit);
+    } else return;
+  }, [remote, staged, buffer, onChanged]);
+
+  // --- Callback
+  const onLocalChange = React.useCallback(
+    (newValue, newError, isReset) => {
+      setModified(!isReset);
+      setBuffer(newValue);
+      setBerror(newError);
+      if (isReset && newValue !== value)
+        onChanged(newValue, newError, isReset);
+    }, [value, onChanged]);
+
+  return {
+    value: modified ? buffer : value,
+    error: modified ? berror : error,
+    reset: reset ?? (modified ? value : undefined),
+    onChanged: onLocalChange,
+  };
+}
+
 /* --------------------------------------------------------------------------*/
 /* --- State Hooks                                                        ---*/
 /* --------------------------------------------------------------------------*/
@@ -119,13 +234,13 @@ export function useState<A>(
 ): FieldState<A> {
   const [value, setValue] = React.useState<A>(defaultValue);
   const [error, setError] = React.useState<FieldError>(undefined);
-  const setState = React.useCallback((newValue: A, newError: FieldError) => {
+  const onChanged = React.useCallback((newValue: A, newError: FieldError) => {
     const localError = validate(newValue, checker) || newError;
     setValue(newValue);
     setError(localError);
-    if (onChange) onChange(newValue, localError);
+    if (onChange) onChange(newValue, localError, false);
   }, [checker, setValue, setError, onChange]);
-  return [value, error, setState];
+  return { value, error, onChanged };
 }
 
 /** Introduces a local state and propagates only non-errors. */
@@ -142,7 +257,12 @@ export function useValid<A>(
       if (!newError) setValue(newValue);
     }, [setValue],
   );
-  return [error ? local : value, error, update];
+  return {
+    value: error ? local : value,
+    error,
+    reset: value,
+    onChanged: update
+  };
 }
 
 /** Provides a new state with a default value. */
@@ -150,8 +270,8 @@ export function useDefault<A>(
   state: FieldState<A | undefined>,
   defaultValue: A,
 ): FieldState<A> {
-  const [value, error, setState] = state;
-  return [value ?? defaultValue, error, setState];
+  const { value, error, reset, onChanged } = state;
+  return { value: value ?? defaultValue, error, reset, onChanged };
 }
 
 /**
@@ -161,15 +281,15 @@ export function useDefault<A>(
 export function useDefined<A>(
   state: FieldState<A>,
 ): FieldState<A | undefined> {
-  const [value, error, setState] = state;
+  const { value, error, reset, onChanged } = state;
   const update = React.useCallback(
-    (newValue: A | undefined, newError: FieldError) => {
+    (newValue: A | undefined, newError: FieldError, doReset) => {
       if (newValue !== undefined) {
-        setState(newValue, newError);
+        onChanged(newValue, newError, doReset);
       }
-    }, [setState],
+    }, [onChanged],
   );
-  return [value, error, update];
+  return { value, error, reset, onChanged: update };
 }
 
 /**
@@ -180,18 +300,18 @@ export function useRequired<A>(
   state: FieldState<A>,
   onError?: string,
 ): FieldState<A | undefined> {
-  const [value, error, setState] = state;
+  const { value, error, reset, onChanged } = state;
   const cache = React.useRef(value);
   const update = React.useCallback(
-    (newValue: A | undefined, newError: FieldError) => {
+    (newValue: A | undefined, newError: FieldError, isReset: boolean) => {
       if (newValue === undefined) {
-        setState(cache.current, onError || 'Required field');
+        onChanged(cache.current, onError || 'Required field', false);
       } else {
-        setState(newValue, newError);
+        onChanged(newValue, newError, !newError && isReset);
       }
-    }, [cache, onError, setState],
+    }, [cache, onError, onChanged],
   );
-  return [value, error, update];
+  return { value, error, reset, onChanged: update };
 }
 
 /**
@@ -202,12 +322,24 @@ export function useChecker<A>(
   state: FieldState<A>,
   checker?: Checker<A>,
 ): FieldState<A> {
-  const [value, error, setState] = state;
-  const update = React.useCallback((newValue: A, newError: FieldError) => {
-    const localError = validate(newValue, checker) || newError;
-    setState(newValue, localError);
-  }, [checker, setState]);
-  return [value, error, update];
+  const { value, error, reset, onChanged } = state;
+  const update = React.useCallback(
+    (newValue: A, newError: FieldError, isReset: boolean) => {
+      const localError = validate(newValue, checker) || newError;
+      onChanged(newValue, localError, !localError && isReset);
+    }, [checker, onChanged]);
+  return { value, error, reset, onChanged: update };
+}
+
+function convertReset<A, B>(
+  fn: (value: A) => B, value: A | undefined
+): B | undefined
+{
+  try {
+    return value ? fn(value) : undefined;
+  } catch(_err) {
+    return undefined;
+  }
 }
 
 /**
@@ -226,7 +358,6 @@ export function useChecker<A>(
    @param input - converting function from `A` to `B`
    @param output - converting function from `B` to `A`
  */
-
 export function useFilter<A, B>(
   state: FieldState<A>,
   input: (value: A) => B,
@@ -234,36 +365,52 @@ export function useFilter<A, B>(
   defaultValue: B,
 ): FieldState<B> {
 
-  const [value, error, setState] = state;
+  const { value, error, reset, onChanged } = state;
   const [localValue, setLocalValue] = React.useState(defaultValue);
   const [localError, setLocalError] = React.useState<FieldError>(undefined);
   const [dangling, setDangling] = React.useState(false);
+  const localReset = convertReset(input, reset);
 
   const update = React.useCallback(
-    (newValue: B, newError: FieldError) => {
+    (newValue: B, newError: FieldError, isReset: boolean) => {
       try {
         const outValue = output(newValue);
         setLocalValue(newValue);
         setLocalError(newError);
         if (isValid(newError)) {
           setDangling(false);
-          setState(outValue, undefined);
+          onChanged(outValue, undefined, isReset);
         }
       } catch (err) {
         setLocalValue(newValue);
         setLocalError(newError || err ? `${err}` : 'Invalid value');
         setDangling(true);
       }
-    }, [output, setState, setLocalValue, setLocalError],
+    }, [output, onChanged, setLocalValue, setLocalError],
   );
 
   if (dangling) {
-    return [localValue, localError, update];
+    return {
+      value: localValue,
+      error: localError,
+      reset: localReset,
+      onChanged: update
+    };
   }
   try {
-    return [input(value), error, update];
+    return {
+      value: input(value),
+      error,
+      reset: localReset,
+      onChanged: update
+    };
   } catch (err) {
-    return [localValue, err ? `${err}` : 'Invalid input', update];
+    return {
+      value: localValue,
+      error: err ? `${err}` : 'Invalid input',
+      reset: localReset,
+      onChanged: update
+    };
   }
 
 }
@@ -277,7 +424,7 @@ export function useLatency<A>(
   state: FieldState<A>,
   latency?: number,
 ): FieldState<A> {
-  const [value, error, setState] = state;
+  const { value, error, reset, onChanged } = state;
   const period = latency ?? 0;
   const [localValue, setLocalValue] = React.useState(value);
   const [localError, setLocalError] = React.useState(error);
@@ -285,26 +432,27 @@ export function useLatency<A>(
   const update = React.useMemo(() => {
     if (period > 0) {
       const propagate = debounce(
-        (lateValue: A, lateError: FieldError) => {
-          setState(lateValue, lateError);
+        (lateValue: A, lateError: FieldError, isReset: boolean) => {
+          onChanged(lateValue, lateError, !lateError && isReset);
           setDangling(false);
         }, period,
       );
-      return (newValue: A, newError: FieldError) => {
+      return (newValue: A, newError: FieldError, isReset: boolean) => {
         setLocalValue(newValue);
         setLocalError(newError);
         setDangling(true);
-        propagate(newValue, newError);
+        propagate(newValue, newError, isReset);
       };
     }
     setDangling(false);
-    return setState;
-  }, [period, setDangling, setState, setLocalValue, setLocalError]);
-  return [
-    dangling ? localValue : value,
-    dangling ? localError : error,
-    update,
-  ];
+    return onChanged;
+  }, [period, setDangling, onChanged, setLocalValue, setLocalError]);
+  return {
+    value: dangling ? localValue : value,
+    error: dangling ? localError : error,
+    reset,
+    onChanged: update,
+  };
 }
 
 /**
@@ -315,19 +463,23 @@ export function useProperty<A, K extends keyof A>(
   property: K,
   checker?: Checker<A[K]>,
 ): FieldState<A[K]> {
-  const [value, error, setState] = state;
-  const update = React.useCallback((newProp: A[K], newError: FieldError) => {
-    const newValue = { ...value, [property]: newProp };
-    const objError = isObjectError(error) ? error : {};
-    const propError = validate(newProp, checker) || newError;
-    const localError = { ...objError, [property]: propError };
-    setState(newValue, isValidObject(localError) ? undefined : localError);
-  }, [value, error, setState, property, checker]);
-  return [
-    value[property],
-    isObjectError(error) ? error[property] : undefined,
-    update
-  ];
+  const { value, error, reset, onChanged } = state;
+  const update = React.useCallback(
+    (newProp: A[K], newError: FieldError, isReset: boolean) => {
+      const newValue = { ...value, [property]: newProp };
+      const objError = isObjectError(error) ? error : {};
+      const propError = validate(newProp, checker) || newError;
+      const localError = { ...objError, [property]: propError };
+      const finalError = isValidObject(localError) ? undefined : localError;
+      onChanged(newValue, finalError, !finalError && isReset);
+    }, [value, error, onChanged, property, checker, ]);
+
+  return {
+    value: value[property],
+    error: isObjectError(error) ? error[property] : undefined,
+    reset: reset && reset[property],
+    onChanged: update
+  };
 }
 
 /**
@@ -338,17 +490,24 @@ export function useIndex<A>(
   index: number,
   checker?: Checker<A>,
 ): FieldState<A> {
-  const [array, error, setState] = state;
-  const update = React.useCallback((newValue: A, newError: FieldError) => {
-    const newArray = array.slice();
-    newArray[index] = newValue;
-    const localError = isArrayError(error) ? error.slice() : [];
-    const valueError = validate(newValue, checker) || newError;
-    localError[index] = valueError;
-    setState(newArray, isValidArray(localError) ? undefined : localError);
-  }, [array, error, setState, index, checker]);
+  const { value, error, reset, onChanged } = state;
+  const update = React.useCallback(
+    (newValue: A, newError: FieldError, isReset: boolean) => {
+      const newArray = value.slice();
+      newArray[index] = newValue;
+      const localError = isArrayError(error) ? error.slice() : [];
+      const valueError = validate(newValue, checker) || newError;
+      localError[index] = valueError;
+      const finalError = isValidArray(localError) ? undefined : localError;
+      onChanged(newArray, finalError, !finalError && isReset);
+    }, [value, error, onChanged, index, checker]);
   const itemError = isArrayError(error) ? error[index] : undefined;
-  return [array[index], itemError, update];
+  return {
+    value: value[index],
+    error: itemError,
+    reset: reset && reset[index],
+    onChanged: update
+  };
 }
 
 /* --------------------------------------------------------------------------*/
@@ -634,11 +793,14 @@ export interface FieldProps<A> extends FilterProps {
 type InputEvent = { target: { value: string } };
 type InputState = [string, FieldError, (evt: InputEvent) => void];
 
-function useChangeEvent(setState: Callback<string>)
-  : ((evt: InputEvent) => void) {
+function useChangeEvent(
+  onChanged: Callback<string>
+): ((evt: InputEvent) => void)
+{
   return React.useCallback(
-    (evt: InputEvent) => { setState(evt.target.value, undefined); },
-    [setState],
+    (evt: InputEvent) => {
+      onChanged(evt.target.value, undefined, false);
+    }, [onChanged],
   );
 }
 
@@ -660,8 +822,8 @@ function useTextInputField(
 ): InputState {
   const checked = useChecker(props.state, props.checker);
   const period = props.latency ?? defaultLatency;
-  const [value, error, setState] = useLatency(checked, period);
-  const onChange = useChangeEvent(setState);
+  const { value, error, onChanged } = useLatency(checked, period);
+  const onChange = useChangeEvent(onChanged);
   return [value || '', error, onChange];
 }
 
@@ -861,8 +1023,8 @@ export function NumberField(props: NumberFieldProps): JSX.Element {
   const css = Utils.classes('dome-xForm-number-field', props.className);
   const checked = useChecker(props.state, props.checker);
   const filtered = useFilter(checked, TEXT_OF_NUMBER, NUMBER_OF_TEXT, '');
-  const [value, error, setState] = useLatency(filtered, latency);
-  const onChange = useChangeEvent(setState);
+  const { value, error, onChanged } = useLatency(filtered, latency);
+  const onChange = useChangeEvent(onChanged);
   const UNITS = units && (
     <label className="dome-text-label dome-xForm-units">{units}</label>
   );
@@ -920,8 +1082,8 @@ export function SpinnerField(props: SpinnerFieldProps): JSX.Element {
   }, [min, max, checker]);
   const checked = useChecker(props.state, fullChecker);
   const filtered = useFilter(checked, TEXT_OF_INPUT_NUMBER, NUMBER_OF_TEXT, '');
-  const [value, error, setState] = useLatency(filtered, latency);
-  const onChange = useChangeEvent(setState);
+  const { value, error, onChanged } = useLatency(filtered, latency);
+  const onChange = useChangeEvent(onChanged);
   const UNITS = units && (
     <label className="dome-text-label dome-xForm-units">{units}</label>
   );
@@ -992,14 +1154,15 @@ const HIDE_SLIDER = `${CSS_SLIDER} dome-xForm-slider-hide`;
    @category Number Fields
  */
 export function SliderField(props: SliderFieldProps): JSX.Element {
-  const { min, max, step = 1, latency = 600, onReset } = props;
+  const { min, max, step = 1, latency = 600 } = props;
   const { disabled } = useContext(props);
   const id = useHtmlFor();
   const css = Utils.classes('dome-xForm-slider-field', props.className);
+  const onReset = props.onReset ?? props.state.reset;
   const checked = useChecker(props.state, props.checker);
   const delayed = useLatency(checked, latency);
   const [label, setLabel] = React.useState<string | undefined>(undefined);
-  const [value, error, setState] = delayed;
+  const { value, error, onChanged } = delayed;
   const labeling = FORMATING(props);
   const onChange = React.useMemo(
     () => {
@@ -1007,7 +1170,7 @@ export function SliderField(props: SliderFieldProps): JSX.Element {
       return (evt: InputEvent) => {
         const v = Number.parseInt(evt.target.value, 10);
         if (!Number.isNaN(v)) {
-          setState(v, undefined);
+          onChanged(v, undefined, false);
           const vlabel = labeling && labeling(v);
           setLabel(vlabel);
           if (vlabel) fadeOut();
@@ -1015,14 +1178,14 @@ export function SliderField(props: SliderFieldProps): JSX.Element {
           setLabel(undefined);
         }
       };
-    }, [labeling, latency, setState, setLabel],
+    }, [labeling, latency, onChanged, setLabel],
   );
   const onDoubleClick = React.useCallback(() => {
     if (onReset) {
-      setState(onReset, undefined);
+      onChanged(onReset, undefined, true);
       setLabel(undefined);
     }
-  }, [onReset, setState, setLabel]);
+  }, [onReset, onChanged, setLabel]);
   const VALUELABEL = labeling && (
     <label className={label ? SHOW_SLIDER : HIDE_SLIDER}>
       {label}
@@ -1182,13 +1345,15 @@ export function CheckboxField(props: CheckboxFieldProps): JSX.Element | null {
 
   if (hidden) return null;
 
-  const [value, , setState] = props.state;
+  const { value, onChanged } = props.state;
   const { label, title, inverted } = props;
   const css = Utils.classes(
     'dome-xForm-field dome-text-label',
     disabled && 'dome-disabled',
   );
-  const onChange = (): void => setState(!value, undefined);
+  const onChange = (): void => {
+    onChanged(!value, undefined, false);
+  };
   return (
     <Checkbox
       className={css}
@@ -1216,8 +1381,8 @@ export function RadioField<A>(props: RadioFieldProps<A>): JSX.Element | null {
 
   if (hidden) return null;
 
-  const [selection, , setState] = props.state;
-  const onSelection = (value: A): void => setState(value, undefined);
+  const { value: selection, onChanged } = props.state;
+  const onSelection = (value: A): void => onChanged(value, undefined, false);
   const { label, title, value } = props;
   const css = Utils.classes(
     'dome-xForm-field dome-text-label',
@@ -1255,9 +1420,9 @@ export interface SelectFieldProps extends FieldProps<string | undefined> {
 export function SelectField(props: SelectFieldProps): JSX.Element {
   const { disabled } = useContext(props);
   const id = useHtmlFor();
-  const [value, error, setState] = useChecker(props.state, props.checker);
-  const onChange =
-    (newValue: string | undefined): void => setState(newValue, undefined);
+  const { value, error, onChanged } = useChecker(props.state, props.checker);
+  const onChange = (newValue: string | undefined): void =>
+    onChanged(newValue, undefined, false);
   const { children, placeholder } = props;
   return (
     <Field