Giter Club home page Giter Club logo

sveltejs-forms's Introduction

sveltejs-forms

npm npm bundle size npm

GitHub Actions Status codecov

Declarative forms for Svelte.

DEMO

Features

  • optional schema-based validation through Yup
  • access to nested properties using paths
  • supports custom components
  • provides Input, Select, Choice components to reduce boilerplate

Install

$ npm i sveltejs-forms

or

$ yarn add sveltejs-forms

How to use

With provided Input, Select, Choice helper components

<script>
  import { Form, Input, Select, Choice } from 'sveltejs-forms';
  import yup from '[email protected]';

  function handleSubmit({ detail: { values, setSubmitting, resetForm } }) {
    setTimeout(() => {
      console.log(values);
      setSubmitting(false);
      resetForm({
        user: { email: '[email protected]' }, // optional
      });
    }, 2000);

    /**
     * {
     *   user: {
     *    email: '[email protected]'
     *   },
     *   password: '123456',
     *   language: 'svelte',
     *   os: 'osx,linux'
     * }
     */
  }

  function handleReset() {
    console.log('form has been reset');
  }

  const schema = yup.object().shape({
    user: yup.object().shape({
      email: yup
        .string()
        .required()
        .email(),
    }),
    password: yup.string().min(4),
    language: yup.string().required(),
    os: yup.string(),
  });

  const langOptions = [
    { id: 'svelte', title: 'Svelte' },
    { id: 'react', title: 'React' },
    { id: 'angular', title: 'Angular' },
  ];

  const osOptions = [
    { id: 'macos', title: 'macOS' },
    { id: 'linux', title: 'Linux ๐Ÿง' },
    { id: 'windows', title: 'Windows' },
  ];

  const initialValues = {
    language: 'svelte',
  };
</script>

<style>
  :global(.sveltejs-forms) {
    background-color: #f8f8f8;
    display: inline-block;
    padding: 1rem;
    border: 1px solid #ccc;
    border-radius: 5px;
  }

  :global(label) {
    font-size: 0.8rem;
    color: #888;
    margin-bottom: 0.2rem;
  }

  :global(.message) {
    font-size: 0.8rem;
    color: #888;
    margin: 0.2rem 0;
    color: #f56565;
  }

  :global(input[type='text']),
  :global(textarea),
  :global(select) {
    width: 100%;
    background-color: white;
    margin: 0;
  }

  :global(input[type='checkbox'] + label) {
    display: inline-block;
    margin-right: 2rem;
  }

  :global(.field) {
    margin-bottom: 1rem;
  }
	
  button {
    border-radius: 5px;
    padding: 0.5rem 1rem;
    margin-right: 1rem;
    color: white;
  }

  button[type='reset'] {
    background-color: #f56565;
  }

  button[type='submit'] {
    background-color: #48bb78;
    width: 80px;
  }
</style>

<Form
  {schema}  <!-- optional -->
  {initialValues} <!-- optional -->
  validateOnBlur={false} <!-- optional, default: true -->
  validateOnChange={false} <!-- optional, default: true -->
  on:submit={handleSubmit}
  on:reset={handleReset}
  let:isSubmitting
  let:isValid
>
  <Input
    name="user.email" <!-- nested field -->
    label="Email Address"
    value="[email protected]" <!-- initial value -->
    placeholder="e.g. [email protected]" />
  <Input name="password" type="password" placeholder="Password" />
  <Select name="language" options={langOptions} />
  <Choice
    name="os"
    options={osOptions}
    disabled
    multiple />
  <button type="reset">Reset</button>
  <button type="submit" disabled={isSubmitting}>Sign in</button>
  <div>The form is valid: {isValid}</div>
</Form>

With custom component:

<script>
  import { Form } from 'sveltejs-forms';
  import Select from 'svelte-select';
  import yup from '[email protected]';

  let svelteSelect;

  function handleSubmit({ detail: { values, setSubmitting, resetForm } }) {
    setTimeout(() => {
      console.log(values);
      setSubmitting(false);
      svelteSelect.handleClear();
      resetForm();
    }, 2000);
  }

  const schema = yup.object().shape({
    food: yup.string().required()
  });

  let items = [
    { value: 'chocolate', label: 'Chocolate' },
    { value: 'pizza', label: 'Pizza' },
    { value: 'cake', label: 'Cake' },
    { value: 'chips', label: 'Chips' },
    { value: 'ice-cream', label: 'Ice Cream' },
  ];
</script>

<Form
  {schema}
  on:submit={handleSubmit}
  let:isSubmitting
  let:setValue
  let:values
  let:errors
  let:touched>

  <Select
    {items}
    bind:this={svelteSelect}
    inputAttributes="{{ name: 'food' }}"
    hasError="{touched['food'] && errors['food']}"
    on:select="{({ detail }) => setValue('food', detail.value)}"
    on:clear="{() => setValue('food', '')}"
    selectedValue="{items.find(item => item.value === values['food'])}"/>

  <button type="submit" disabled={isSubmitting}>Submit</button>
</Form>

Slot props

Name Type
isSubmitting boolean
isValid boolean
setValue(path, value) function
touchField(path) function
validate() function
values object
errors object
touched object

Contributions

All contributions are welcome.

sveltejs-forms's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar mdauner avatar oncode avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

sveltejs-forms's Issues

how to specify a class name into Input component?

Describe the bug
There is no way to set class attribute to Input component, when by example you're using a css framework like bootstrap, and I can not set class="form-input", it is not being applied. since component does not receiving class attribute as it is currently.

Support `label` on `Input` and `Select`

Describe the solution you'd like
For a label element to be automatically created (within the div) when specified; the value for the parameter label should be used as the label proper. (reuse the name as id for the input; and referenced by the label)

Describe alternatives you've considered
I've tried creating label elements alongside the Input; however due to the wrapping div the label is not adjacent to the input element. Moreover since the created input lacks an id the label is contextually useless. Using placeholder is acceptable for text inputs, however a label is still needed for Select.

Input.svelte erroring with $$restProps is an illegal variable name

Describe the bug
When trying to use the library, the svelte processor will error with
$$restProps is an illegal variable name

To Reproduce
Steps to reproduce the behavior:

  1. Add library to svelte/sapper project
  2. Run npm run dev
  3. See error in terminal

Expected behavior
The svelte/sapper app will build.

Additional context
This is also erroring on the demo page.

Unchecked checkbox not reporting

Describe the bug
An unchecked checkbox still gives a value. As expected, when a box is checked its name will appear in the values, however, when the box is unchecked (after having been checked) its name still appears in values.

To Reproduce
Steps to reproduce the behavior:

  1. Create a Form with an Input of type checkbox and a submit button; use a console.log to print the values of a submitted Form.
  2. Allow page to render
  3. Click the checkbox
  4. Unclick the checkbox
  5. Click the submit button
  6. Observe the console to find the name of the checkbox in the values
  7. Reload the page
  8. Hit submit without clicking the checkbox
  9. Observe the console to find that the name of the checkbox is not in values

Expected behavior
When a checkbox is de-selected, its name ought to be removed from values.

Desktop (please complete the following information):

  • OS: Ubuntu 18.04 (64-bit)
  • Browser: Chromium
  • Version: 78.0.3904.108 (Official Build)

Error reported in REPL of your DEMO

Describe the bug
In your DEMO link, there is an error, so the demo can't work

with ?version=3.22.3 it works.

Error reported:
$$restProps is an illegal variable name (Input.svelte:22:36)

Input Component extension: define a way to set attributes

According to issue #120, there's no way to define a class for the input, but not also: there's no way to define any attribute except name, placeholder or type.
Passing some attributes to the input should be useful to define a custom ID, or if the input is disabled or readonly etc.

Could be possible to define a prop with all attributes we want to pass to the Input in order to customize it?

In addition could also be useful add a slot to override the label for example if we want to add an icon or we want to attach a class.

When touched, should validate on keyup

Is your feature request related to a problem? Please describe.
When I have an error message in a field, I expect that as I fix it, the error should go away.
e.g. it says my email is invalid, so I fix it: [email protected].. but the error is still there. When I click away, the error is gone.

I'd almost describe this as a bug, but I'll settle for a feature request for now.

Describe the solution you'd like
We don't want evaluation on every keyup -- it's uncomfortable for a user to start typing their email and see a big ERROR -- "Dummy, I'm just getting started!" but once an error is shown (or when it's been touched before) I would like the error to disappear as soon as I've fixed it.

Screenshots
https://www.awesomescreenshot.com/video/141161 (upto 22 seconds)

Sample code error: Checkmark misvalidation on blur

Describe the bug

The sample code from https://github.com/mdauner/sveltejs-forms#how-to-use produces an issue with onblur.

To Reproduce
Steps to reproduce the behavior:

  1. Go to https://svelte.dev/repl/b8a2d021a1484700856a17012b3c0602?version=3.22.3
  2. Click 2x operating systems.
  3. Uncheck 1x operating system.
  4. Click "submit"

Expected behavior
At step 2, upon clicking a second operating system, the error should have gone away.
At step 3, upon unchecking 1x OS, the error should remain.

Screenshots
22 seconds in on https://www.awesomescreenshot.com/video/141161

Desktop (please complete the following information):

  • OS: win10
  • Browser chrome
  • Version 83.0.4103.61 (Official Build) (64-bit)

CSS not working - discarded as unused

Describe the bug
When using the code from the readme, or something like it, there's no styling on error.

<style lang="scss" global>
  .sveltejs-forms {
    background-color: lightgray;
    display: inline-block;
    padding: 1rem;

    .field {
      margin-bottom: 1rem;
      &.error {
        input {
          border: 1px solid red;
        }
        .message {
          margin-top: 0.2rem;
          color: red;
          font-size: 0.8rem;
        }
      }
    }
  }
</style>

Actually svelte/rollup choked on the & but once I just defined .error it didn't work.

I figure out this was because it was being discarded as unused. the global didn't seem to help.

I see that in the REPL example, you used :global(.error) and that works ok. Please update the examples (with valid svelte version) and how to use styles.

Thanks!

Set the Input value

There no way to set the input value of the Input object.

I will like to bind the value property of the item and is not possible.

example:

Backend errors

In order to reuse the form errors management also for backend messages (Eg: duplicated email on signup), could be useful add the errors store to the object passed as parameter to the submit event.

[offering pr] TypeScript Support

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

It is frustrating to have to build custom types to run alongside this library. I figure, if I'm going to do it anyway, I'd like to see if you'd accept a PR to add TS support.

Describe the solution you'd like
A clear and concise description of what you want to happen.

Write and bundle TypeScript types with this package for those of us using TypeScript.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

We were going to try to write our own types to use alongside this library to get strong typing. We're ending up having to import from 'sveltejs-forms/src/components/Form.svelte' to get type safety, and ideally we wouldn't rebuild from source if at all possible.

Additional context
Add any other context or screenshots about the feature request here.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.