Table of Contents
Concept
Allow this library to contain all state management of forms whether they be single step, or multiple.
Components
There are four exposed components that can be used as of now:
Field
has several underlying components:
-
Checkbox
- This contains checkbox groups
-
Input
- This contains input field types:
- Text
- Password
- Search
- Number
- Tel
- Range
- File
- Date
- Datetime Local
- This contains input field types:
- Radio
- Select
- Textarea
There's an additional component that is used when giving Form
a config: Section
.
Props
You can pass any props into the exposed components and they'll be passed to the primary element. However, there are a few exceptions:
Form
Form
exposes several props which are related to the multi-step control:
-
prev
, this is a function for form control -
next
, this is a function for form control -
controlsClass
, custom class passed to the controls container
Form
also has a config
prop w/ optional content wrapper:
-
config
, used for generating form (take a look at examples) -
ContentWrap
, svelte component used to wrap sections
Form
passes two props back as well: store
and multi
. These can be accessed using the let:
directive:
<script lang="ts">
import { Form } from 'svelte-multi';
</script>
<Form let:store let:multi>
...
</Form>
store
can be passed into Form
if there's a separate implentation of IndexableJsonValue
you'd prefer:
<script lang="ts">
import { writable } from 'svelte/store';
import type { Writable } from 'svelte/store';
import { Form } from 'svelte-multi';
import type { IndexableJsonValue } from 'svelte-multi';
const store: Writable<IndexableJsonValue> = writable({});
</script>
<Form {store}>
...
</Form>
Form
also controls a few built-in function directives with returned CustomEvent
s:
-
on:submit
, with preventDefault, to pass the store back to you (THIS DOES PREVENT ACTION FROM BEING USED):
<script lang="ts">
import { Form } from 'svelte-multi';
import type { SubmitType } from 'svelte-multi';
const onSubmit = (ev: CustomEvent<SubmitType>) => {
const {
e, // Original submit event
store, // Will either be form control store, or one you declared
} = ev.detail;
console.log(e, store);
};
</script>
<Form on:submit={onSubmit}>
...
</Form>
-
on:contextmenu
:
<script lang="ts">
import { Form } from 'svelte-multi';
const onContextMenu = (ev: CustomEvent) => {
const {
e, // Original submit event
} = ev.detail;
console.log(e);
};
</script>
<Form on:contextmenu={onContextMenu}>
...
</Form>
-
on:click
:
<script lang="ts">
import { Form } from 'svelte-multi';
const onClick = (ev: CustomEvent) => {
const {
e, // Original submit event
} = ev.detail;
console.log(e);
};
</script>
<Form on:click={onClick}>
...
</Form>
Finally, Form
has a few named slots that can be used as controls, prev
, next
, and submit
:
<script lang="ts">
import { Form } from 'svelte-multi';
</script>
<Form let:prev let:next>
...
<button slot="prev" on:click|preventDefault={prev}>Prev</button>
<button slot="next" on:click|preventDefault={next}>Next</button>
<input slot="submit" type="submit" placeholder="Submit" />
</Form>
Step
Step
is technically just a wrapper, and exposes only a single prop:
-
name
, which is used as the overall header/label for the step.
Field
Field
is a bit more complex as it takes field
(which are the field props) and initial
.
-
field
consists of the following information:
type FieldProps = {
id: string;
name: string;
type: FieldType;
disabled?: Maybe<boolean>;
readonly?: Maybe<boolean>;
required?: Maybe<boolean>;
/** For text, password, email, search, tel, textarea, or number fields */
placeholder?: Maybe<string>;
/** For text, password, email, search, tel, select, or textarea fields */
autocomplete?: Maybe<boolean>;
/** For number, range, date, and datetime-local fields */
step?: Maybe<number>;
/** For number, range, date, and datetime-local fields */
min?: Maybe<number>;
/** For number, range, date, and datetime-local fields */
max?: Maybe<number>;
/** For select and file fields */
multiple?: Maybe<boolean>;
/** For textarea fields */
rows?: Maybe<number>;
/** For textarea fields */
cols?: Maybe<number>;
/** For tel fields */
pattern?: Maybe<string>;
/** For file fields */
accept?: Maybe<string>;
/** Optional prop for any field */
label?: Maybe<LabelProps>;
/** Optional prop for any field */
classes?: string;
/** Optional path for nested values in store */
path?: Maybe<Path>;
/** For radio and checkbox fields */
items?: Maybe<Item[]>;
};
The only required props are id
, name
, and type
.
You'll notice a few other types in here, which consist of FieldType
, LabelProps
, Path
, and Item
; here they are:
FieldType
enum FieldType {
Text = 'text',
Password = 'password',
Email = 'email',
Search = 'search',
Number = 'number',
Textarea = 'textarea',
Date = 'date',
DatetimeLocal = 'datetime-local',
Tel = 'tel',
Range = 'range',
File = 'file',
Checkbox = 'checkbox',
Select = 'select',
Radio = 'radio',
}
LabelProps
type LabelProps = {
/** Printed text of label */
text: string;
/** Optional prop for label */
classes?: string;
};
Path
/** Array of strings and numbers that allow access to deep nested values in form stores. */
type Path = Array<string | number>;
Item
type Item = {
/** Unique ID of item */
id: string;
/** Internal value of item */
value: string;
/** Printed text of item */
text: string;
/** Classes used by item wrapper */
wrapperClasses?: string;
/** Classes used by item text */
textClasses?: string;
};
That's a bit much, but it's fairly straight forward.
-
FieldType
are the types that are allowed without adverse effects. -
LabelProps
are the props passed to the optional label. -
Path
is used with thestore
to access nested values:
<script lang="ts">
import { writable } from 'svelte/store';
import { Form, Field, FieldType } from 'svelte-multi';
const store = writable({
test: {
testing: [
{
value: '',
},
],
},
});
</script>
<Form {store}>
<Field
{store}
field={{ id: '1', name: '1', type: FieldType.Text, path: ['test', 'testing', 0, 'value'] }} />
</Form>
This allows for the value in store to be updated properly in the nest.
-
Item
is used with radio and checkbox as these are group fields:
<script lang="ts">
import { Form, Field, FieldType } from 'svelte-multi';
</script>
<Form let:store>
<Field
{store}
field={{
id: '1',
name: '1',
type: FieldType.Radio,
items: [
{ id: 'item1', value: 'item1', text: 'item1' },
{ id: 'item2', value: 'item2', text: 'item2' }
],
}} />
</Form>
Note that radio will return a string value, and checkbox will return an array of string values.
ToC (Table of Contents)
This is a generic ToC that uses the form name, steps, and sections (generated by config). There are several exposed props:
formName
-
stepsWithSections
, of typeStep[]
-
stepsWithoutSections
, of typeWritable<IndexableJsonValue>
, this would bemulti
returned fromForm
-
sections
, of typeSection[]
stepClass
sectionsWrapperClass
sectionsClass
The class props will be passed like this:
<h1>{formName}</h1>
<ul {...$$restProps}>
...
{#each steps as step}
<li class={stepClass}>
...
<ul class={sectionsWrapperClass}> <!-- Used only when passing generated sections -->
...
{#each step.sections as section}
<li class={sectionsClass}>
...
</li>
{/each}
...
</ul>
...
</li>
{/each}
...
</ul>