Input

Accept a single line of text, such as a name, email address, or search query.

Live preview
Interact with the component to see results here.
View code
HTML
<sy-input
  label="Name"
  placeholder="Enter a name"
  type="text"
  size="medium"
  status="default"
  clearable
  id="sample"
  name="name"
></sy-input>

Usage guide

#

Use to accept a short, single-line value. Explain its purpose with a Label and use Placeholder for an example.

  1. Write the error message in the error slot.

    Inside the component, add <span slot="error">Error message</span>. You can include links and other guidance as well as text. For inputs supporting noNativeValidity, enable it to show this guidance instead of a browser popup. Switch always displays errors below the component.

  2. Report business rule failures with setCustomError().

    For example, if the server rejects a duplicate value, update the error slot and call setCustomError(). This method does not take a message argument. A custom error also blocks form submission.

  3. Clear the error after resolving it and check whether submission is allowed.

    Use clearCustomError() to clear a business rule error. Required-field and format validation remain active. await checkValidity() returns true or false; reportValidity() validates and displays errors. Read valid named values through FormData on submission.

Plain text

Choose a type matching the input's purpose, such as text, search, or password.

Contact details and addresses

Use email, tel, or url to identify the expected value type.

Numeric input

You can use number. For range, step, and precision control, use Input Number.

Examples

#

Email and password

The type determines input behavior and default validation rules.

View code
HTML
<div style="display:grid;gap:16px;width:100%">
  <sy-input
    type="email"
    label="Email"
    placeholder="name@example.com"
  ></sy-input>
  <sy-input
    type="password"
    label="Password"
    value="syidax-demo"
  ></sy-input>
</div>

Prefix and suffix elements

Use the prefix and suffix slots to add units or context. Slot content is not included in the actual value.

View code
HTML
<sy-input
  label="Website"
  placeholder="example.com"
  clearable
><span slot="prefix">https://</span><span slot="suffix">↗</span></sy-input>

Input status

Visually indicate success, warning, or error. Changing status alone does not replace form validation.

View code
HTML
<div style="display:grid;gap:16px;width:100%">
  <sy-input
    status="default"
    label="default"
    value="Syidax"
  ></sy-input>
  <sy-input
    status="success"
    label="success"
    value="Syidax"
  ></sy-input>
  <sy-input
    status="warning"
    label="warning"
    value="Syidax"
  ></sy-input>
  <sy-input
    status="error"
    label="error"
    value="Syidax"
  ></sy-input>
</div>

Disabled and read only

From top to bottom: default, disabled, and read only. Disabled fields cannot receive focus or input. Read-only fields keep their value but prevent editing.

View code
HTML
<div style="display:grid;gap:16px;width:100%">
  <sy-input
    label="Name"
    value="Alex Kim"
    clearable
  ></sy-input>
  <sy-input
    label="Name"
    value="Alex Kim"
    clearable
    disabled
  ></sy-input>
  <sy-input
    label="Name"
    value="Alex Kim"
    clearable
    readonly
  ></sy-input>
</div>

Change the value and input type

Changing type or value on the same input updates both the actual input and its validation state.

View code
HTML
<sy-input
  type="password"
  value="syidax-demo"
  label="Externally controlled input"
  clearable
  id="sample"
></sy-input>
<div class="demo-actions">
  <sy-button id="as-text">Switch to text</sy-button>
  <sy-button id="invalid-email">Set an invalid email</sy-button>
  <sy-button id="valid-email">Set a valid email</sy-button>
</div>
<output id="controlled-result" aria-live="polite"></output>

<script type="module">
  await (root => {
    const input = root.querySelector('#sample');
    const result = root.querySelector('#controlled-result');
    const apply = async (type, value) => {
      input.type = type;
      input.value = value;
      result.textContent =
        `${type} · ${await input.checkValidity() ? _msg("m_c5619d3358dc") : _msg("m_05b136149408")} · ${await input.getStatus() || _msg("m_79ca43ef8a7f")}`;
    };
    root.querySelector('#as-text').addEventListener('click', () => apply('text', 'Syidax'));
    root.querySelector('#invalid-email').addEventListener('click', () => apply('email',
      'invalid'));
    root.querySelector('#valid-email').addEventListener('click', () => apply('email',
      'name@example.com'));
  })(document);
</script>

Focus control

After an external action, use setFocus to focus the input and setBlur to remove focus.

View code
HTML
<sy-input label="Project name" id="sample"></sy-input>
<div class="demo-actions"
  style="display:flex;flex-wrap:wrap;gap:8px;margin-top:16px"
>
  <sy-button id="action-0" size="small">Focus input</sy-button>
  <sy-button id="action-1" size="small">Blur</sy-button>
</div>
<output id="demo-result" aria-live="polite"></output>

<script type="module">
  const describeResult = value => JSON.stringify(value, (_key, item) => {
    if (item instanceof File) return {
      name: item.name,
      size: item.size,
      type: item.type
    };
    if (item instanceof Element) return `<${item.localName}>`;
    return item;
  }) ?? 'Done';
  const actionTarget0 = document.querySelector("#sample");
  document.querySelector('#action-0').addEventListener('click', async () => {
    const result = await actionTarget0.setFocus();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  const actionTarget1 = document.querySelector("#sample");
  document.querySelector('#action-1').addEventListener('click', async () => {
    const result = await actionTarget1.setBlur();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
</script>

Events and payloads

Interact with the component and inspect the latest event name and detail. The code includes subscriptions to events emitted by this component and its children.

View code
HTML
<sy-input
  label="Name"
  placeholder="Enter a name"
  type="text"
  size="medium"
  status="default"
  clearable
  id="sample"
  name="name"
></sy-input>
<output id="demo-events" aria-live="polite">Interact with the component to see
  its latest event and payload.</output>

<script type="module">
  const describeResult = value => JSON.stringify(value, (_key, item) => {
    if (item instanceof File) return {
      name: item.name,
      size: item.size,
      type: item.type
    };
    if (item instanceof Element) return `<${item.localName}>`;
    return item;
  }) ?? 'Done';
  for (const name of ["changed", "blured", "focused", "clear"]) {
    document.addEventListener(name, event => {
      document.querySelector('#demo-events').textContent =
        `${event.target.localName} · ${name}: ${describeResult(event.detail)}`;
    });
  }
</script>

Input icons and help text

prefix-icon and suffix-icon provide icon areas at each end of the input. Use message for persistent help text and error for validation feedback.

View code
HTML
<sy-input
  placeholder="Email"
  type="email"
  label="Contact"
><span slot="prefix-icon" aria-hidden="true">@</span><span slot="suffix-icon"
    aria-hidden="true"
  >✉</span><span slot="message">Enter your work email address.</span><span
    slot="error"
  >Check the email format.</span></sy-input>

Forms and validation

Submit an empty value to trigger required-field validation. Enter a value and submit to inspect the form data, then try enabling and clearing a custom error.

View code
HTML
<form style="display:grid;gap:16px">
  <sy-input
    name="field"
    required
    type="email"
    label="Email"
    clearable
    id="sample"
  ><span slot="error">Enter a valid email address.</span></sy-input>
  <div style="display:flex;flex-wrap:wrap;gap:8px">
    <sy-button type="submit" variant="primary">Submit</sy-button>
    <sy-button type="reset">Reset</sy-button>
  </div>
</form>
<div class="demo-actions"
  style="display:flex;flex-wrap:wrap;gap:8px;margin-top:16px"
>
  <sy-button id="action-0" size="small">Check validity</sy-button>
  <sy-button id="action-1" size="small">Show error</sy-button>
  <sy-button id="action-2" size="small">Clear error</sy-button>
</div>
<output id="demo-result" aria-live="polite"></output>

<script type="module">
  const describeResult = value => JSON.stringify(value, (_key, item) => {
    if (item instanceof File) return {
      name: item.name,
      size: item.size,
      type: item.type
    };
    if (item instanceof Element) return `<${item.localName}>`;
    return item;
  }) ?? 'Done';
  const actionTarget0 = document.querySelector("#sample");
  document.querySelector('#action-0').addEventListener('click', async () => {
    const result = await actionTarget0.checkValidity();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  const actionTarget1 = document.querySelector("#sample");
  document.querySelector('#action-1').addEventListener('click', async () => {
    const result = await actionTarget1.setCustomError();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  const actionTarget2 = document.querySelector("#sample");
  document.querySelector('#action-2').addEventListener('click', async () => {
    const result = await actionTarget2.clearCustomError();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  document.querySelector('form').addEventListener('submit', event => {
    event.preventDefault();
    document.querySelector('#demo-result').textContent = describeResult([...new FormData(event
      .currentTarget)]);
  });
</script>

Disable a form group

Use fieldset to lock or unlock a group. Individually disabled fields remain disabled and are excluded from FormData.

View code
HTML
<form>
  <fieldset id="input-group">
    <legend>Project owner</legend>
    <sy-input
      label="Assignee"
      name="owner"
      value="Alex"
      required
    ></sy-input>
    <sy-input
      label="Locked field"
      name="locked"
      value="Admin"
      disabled
    ></sy-input>
  </fieldset>
  <div class="demo-actions">
    <sy-button id="lock-group">Lock group</sy-button>
    <sy-button id="unlock-group">Unlock group</sy-button>
    <sy-button type="submit">Submit</sy-button>
    <sy-button type="reset">Reset</sy-button>
  </div>
</form>
<output id="demo-result" aria-live="polite"></output>

<script type="module">
  const describeResult = value => JSON.stringify(value, (_key, item) => {
    if (item instanceof File) return {
      name: item.name,
      size: item.size,
      type: item.type
    };
    if (item instanceof Element) return `<${item.localName}>`;
    return item;
  }) ?? 'Done';
  await (root => {
    const group = root.querySelector('#input-group');
    root.querySelector('#lock-group').addEventListener('click', () => group.disabled = true);
    root.querySelector('#unlock-group').addEventListener('click', () => group.disabled = false);
  })(document);
  document.querySelector('form').addEventListener('submit', event => {
    event.preventDefault();
    document.querySelector('#demo-result').textContent = describeResult([...new FormData(event
      .currentTarget)]);
  });
</script>

Read validation results and error states

Validate before submitting or display errors on screen. Check an empty required field, then fill it to see how the return value changes. Querying the state distinguishes custom errors from required-field errors.

View code
HTML
<form style="display:grid;gap:16px">
  <sy-input
    name="field"
    required
    type="email"
    label="Email"
    clearable
    id="sample"
  ><span slot="error">Enter a valid email address.</span></sy-input>
  <div style="display:flex;flex-wrap:wrap;gap:8px">
    <sy-button type="submit" variant="primary">Submit</sy-button>
    <sy-button type="reset">Reset</sy-button>
  </div>
</form>
<div class="demo-actions"
  style="display:flex;flex-wrap:wrap;gap:8px;margin-top:16px"
>
  <sy-button id="action-0" size="small">Check validity</sy-button>
  <sy-button id="action-1" size="small">Show error</sy-button>
  <sy-button id="action-2" size="small">Clear error</sy-button>
  <sy-button id="action-3" size="small">Validate with errors</sy-button>
  <sy-button id="action-4" size="small">Query validation state</sy-button>
</div>
<output id="demo-result" aria-live="polite"></output>

<script type="module">
  const describeResult = value => JSON.stringify(value, (_key, item) => {
    if (item instanceof File) return {
      name: item.name,
      size: item.size,
      type: item.type
    };
    if (item instanceof Element) return `<${item.localName}>`;
    return item;
  }) ?? 'Done';
  const actionTarget0 = document.querySelector("#sample");
  document.querySelector('#action-0').addEventListener('click', async () => {
    const result = await actionTarget0.checkValidity();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  const actionTarget1 = document.querySelector("#sample");
  document.querySelector('#action-1').addEventListener('click', async () => {
    const result = await actionTarget1.setCustomError();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  const actionTarget2 = document.querySelector("#sample");
  document.querySelector('#action-2').addEventListener('click', async () => {
    const result = await actionTarget2.clearCustomError();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  const actionTarget3 = document.querySelector("#sample");
  document.querySelector('#action-3').addEventListener('click', async () => {
    const result = await actionTarget3.reportValidity();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  const actionTarget4 = document.querySelector("#sample");
  document.querySelector('#action-4').addEventListener('click', async () => {
    const result = await actionTarget4.getStatus();
    document.querySelector('#demo-result').textContent = describeResult(result);
  });
  document.querySelector('form').addEventListener('submit', event => {
    event.preventDefault();
    document.querySelector('#demo-result').textContent = describeResult([...new FormData(event
      .currentTarget)]);
  });
</script>

Custom error messages

Display a custom error for server-side duplicate checks or business rules. Change the message below and submit to verify that it is blocked. After clearing the error, required-field constraints must still be satisfied.

View code
HTML
<label for="error-message">Error message to display</label><input
  id="error-message"
  value="The server did not accept this value. Please review it."
  type="text"
>
<form style="display:grid;gap:16px">
  <sy-input
    nonativevalidity
    name="field"
    required
    type="email"
    label="Email"
    clearable
    id="sample"
  ><span slot="error">Enter a valid email address.</span></sy-input>
  <div style="display:flex;flex-wrap:wrap;gap:8px">
    <sy-button type="submit" variant="primary">Submit</sy-button>
    <sy-button type="reset">Reset</sy-button>
  </div>
</form>
<div class="demo-actions">
  <sy-button id="show-custom-error" variant="primary">Show error</sy-button>
  <sy-button id="clear-custom-error">Clear error</sy-button>
</div>
<output id="custom-error-result" aria-live="polite"></output>
<output id="demo-result" aria-live="polite"></output>

<script type="module">
  const describeResult = value => JSON.stringify(value, (_key, item) => {
    if (item instanceof File) return {
      name: item.name,
      size: item.size,
      type: item.type
    };
    if (item instanceof Element) return `<${item.localName}>`;
    return item;
  }) ?? 'Done';
  await (async function customErrorSetup(root) {
    const field = root.querySelector('#sample');
    const message = root.querySelector('[slot="error"]');
    const input = root.querySelector('#error-message');
    const output = root.querySelector('#custom-error-result');
    const update = async () => {
      message.textContent = input.value.trim() || _msg("m_4eea8cef81c6");
      await field.setCustomError();
      output.textContent = _msg("m_e00bd46236d3", [message.textContent]);
    };
    input.addEventListener('input', update);
    root.querySelector('#show-custom-error').addEventListener('click', update);
    root.querySelector('#clear-custom-error').addEventListener('click', async () => {
      await field.clearCustomError();
      output.textContent = await field.checkValidity() ? _msg("m_c454251167b2") : _msg(
        "m_5b8cb48627e5");
    });
    root.querySelector('form').addEventListener('invalid', () => {
      output.textContent = _msg("m_c702c7778166");
    }, true);
    root.querySelector('form').addEventListener('reset', () => {
      output.textContent = _msg("m_b90c2b4dc30f");
    });
    await update();
  })(document);
  document.querySelector('form').addEventListener('submit', event => {
    event.preventDefault();
    document.querySelector('#demo-result').textContent = describeResult([...new FormData(event
      .currentTarget)]);
  });
</script>

API reference

#

Hover over a name or focus it with the keyboard to see the code. On touch screens, tap the name.

<sy-input>

Properties

Attribute / PropertyTypeDefaultDescription
booleanfalseFocus the input when it first connects.
booleanfalseHide the default border.
booleanfalseShow a button to clear the current value.
booleanfalseBlock user interaction and keyboard focus.
string""Label describing the item.
numberundefinedMaximum allowed string length.
numberundefinedMinimum allowed string length.
string""Field name used in FormData.
string""Placeholder shown when the value is empty.
booleanfalseDisplay the current value while preventing edits.
booleanfalseFail form validation when no value is provided.
"small" | "medium" | "large""medium"Component size.
'default' | 'warning' | 'error' | 'success''default'Visually represent default, success, warning, or error states.
string""Current value or item identifier.
"password" | "search" | "text""text"Legacy-compatible input type. Use type in new code.
booleanfalseUse the app's error UI instead of the browser's built-in error display. checkValidity still performs validation.
'text' | 'password' | 'email' | 'number' | 'tel' | 'url' | 'search''text'HTML input type or button action type.
string""Help text about the input state.

Events

EventDetailDescription
CustomEvent<{ value: string; isValid: boolean; status: string }>Emitted when the value or selection state changes.
CustomEvent<{ value: string; isValid: boolean; status: string }>Emitted when focus is lost.
CustomEvent<{ value: string; isValid: boolean; status: string }>Emitted when focus is received.
CustomEvent<void>Emitted when the input value is cleared.

Methods

MethodReturnsDescription
Promise<void>Move keyboard focus to the input or action element.
Promise<void>Remove focus from the input element.
Promise<boolean>Return true if the current constraints are satisfied, otherwise false.
Promise<boolean>Validate the current value and display errors to the user.
Promise<void>Set a custom error state.
Promise<void>Clear the custom error state.
Promise<"" | "custom" | "valueMissing" | "tooShort" | "tooLong" | "typeMismatch" | "badInput" | "stepMismatch">Return the current validation state.

Slots

SlotDescription
Supplementary content before the input value.
Icon before the input value.
Validation error message.
Input help message.
Supplementary content after the input value.
Icon after the input value.