Build forms with GraphQL

A presentation at React Europe 2019 in May 2019 in Paris, France by Charly Poly

Slide 1

Slide 1

Build forms with GraphQL @whereischarly

Slide 2

Slide 2

#whoami Charly POLY - Senior Software Engineer at @whereischarly

Slide 3

Slide 3

#whoami I @whereischarly ❤ Front-end development

Slide 4

Slide 4

#whoami I @whereischarly ❤ Single Page Applications

Slide 5

Slide 5

Single Page Applications @whereischarly

Slide 6

Slide 6

Single Page Applications State management @whereischarly

Slide 7

Slide 7

Single Page Applications State management @whereischarly Routing

Slide 8

Slide 8

Single Page Applications State management Routing Crypto @whereischarly

Slide 9

Slide 9

Single Page Applications State management Routing Crypto PWA @whereischarly

Slide 10

Slide 10

Single Page Applications State management Routing Crypto Offline capabilities PWA @whereischarly

Slide 11

Slide 11

Single Page Applications State management Routing Crypto Offline capabilities PWA @whereischarly Rendering

Slide 12

Slide 12

Single Page Applications @whereischarly

Slide 13

Slide 13

Single Page Applications Forms @whereischarly

Slide 14

Slide 14

Single Page Applications Forms @whereischarly = manual and repetitive task

Slide 15

Slide 15

Forms: glue between UI and APIs @whereischarly

Slide 16

Slide 16

Forms: glue between UI and APIs @whereischarly

Slide 17

Slide 17

Forms: glue between UI and APIs @whereischarly

Slide 18

Slide 18

Forms: glue between UI and APIs @whereischarly

Slide 19

Slide 19

Forms: glue between UI and APIs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 // Render Prop import React from ‘react’; import { Formik, Form, Field, ErrorMessage } from ‘formik’; import { CustomInputComponent, CustomPasswordComponent } from ‘./common/components’; import { UserService } from ‘./services/UserService’; const Basic = () => ( <Formik validate={values => { let errors = {}; if (!values.email) { errors.email = ‘Required’; } else if ( !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}$/i.test(values.email) ) { errors.email = ‘Invalid email address’; } return errors; }} onSubmit={(values, { setSubmitting }) => UserService.update(values, setSubmitting) } > {({ isSubmitting }) => ( <Form> <Field type=”email” name=”email” component={CustomInputComponent} /> <ErrorMessage name=”email” component=”div” /> <Field type=”password” name=”password” component={CustomPasswordComponent} /> <ErrorMessage name=”password” component=”div” /> <button type=”submit” disabled={isSubmitting}> Submit </button> </Form> )} </Formik> ); export default Basic;

Slide 20

Slide 20

Forms: glue between UI and APIs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 // Render Prop import React from ‘react’; import { Formik, Form, Field, ErrorMessage } from ‘formik’; import { CustomInputComponent, CustomPasswordComponent } from ‘./common/components’; import { UserService } from ‘./services/UserService’; const Basic = () => ( <Formik validate={values => { let errors = {}; if (!values.email) { errors.email = ‘Required’; } else if ( !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}$/i.test(values.email) ) { errors.email = ‘Invalid email address’; } return errors; }} onSubmit={(values, { setSubmitting }) => UserService.update(values, setSubmitting) } > {({ isSubmitting }) => ( <Form> <Field type=”email” name=”email” component={CustomInputComponent} /> <ErrorMessage name=”email” component=”div” /> <Field type=”password” name=”password” component={CustomPasswordComponent} /> <ErrorMessage name=”password” component=”div” /> <button type=”submit” disabled={isSubmitting}> Submit </button> </Form> )} </Formik> ); export default Basic;

Slide 21

Slide 21

Forms: glue between UI and APIs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 // Render Prop import React from ‘react’; import { Formik, Form, Field, ErrorMessage } from ‘formik’; import { CustomInputComponent, CustomPasswordComponent } from ‘./common/components’; import { UserService } from ‘./services/UserService’; const Basic = () => ( <Formik validate={values => { let errors = {}; if (!values.email) { errors.email = ‘Required’; } else if ( !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}$/i.test(values.email) ) { errors.email = ‘Invalid email address’; } return errors; }} onSubmit={(values, { setSubmitting }) => UserService.update(values, setSubmitting) } > {({ isSubmitting }) => ( <Form> <Field type=”email” name=”email” component={CustomInputComponent} /> <ErrorMessage name=”email” component=”div” /> <Field type=”password” name=”password” component={CustomPasswordComponent} /> <ErrorMessage name=”password” component=”div” /> <button type=”submit” disabled={isSubmitting}> Submit </button> </Form> )} </Formik> ); export default Basic;

Slide 22

Slide 22

Forms: glue between UI and APIs “Forms handle the experience that users have with data” @whereischarly

Slide 23

Slide 23

Story: Improving forms development @whereischarly

Slide 24

Slide 24

Speeding up form development @whereischarly 1 class Form extends ModuleForm { 2 fields: FieldsDefinitions = { 3 id: ‘none’, 4 email: ‘none’, 5 picture_path: { 6 type: ‘image’, transformations: ‘h_200,w_200,r_max,c_fill’ 7 }, 8 first_name: ‘string*’, 9 last_name: ‘string*’, 10 username: ‘string*’, 11 job_title: ‘string’, 12 company_name: ‘string’, 13 language: { 14 type: ‘select*’, 15 component: LanguageSelectView, 16 valueProperty: ‘code’, 17 values: supportedLanguages, 18 moduleName: ‘attachment’ 19 } 20 }; 21 22 constructor() { 23 super(‘UserForm’, ‘user’); 24 } 25 }

Slide 25

Slide 25

Speeding up form development @whereischarly 1 class Form extends ModuleForm { 2 fields: FieldsDefinitions = { 3 id: ‘none’, 4 email: ‘none’, 5 picture_path: { 6 type: ‘image’, transformations: ‘h_200,w_200,r_max,c_fill’ 7 }, 8 first_name: ‘string*’, 9 last_name: ‘string*’, 10 username: ‘string*’, 11 job_title: ‘string’, 12 company_name: ‘string’, 13 language: { 14 type: ‘select*’, 15 component: LanguageSelectView, 16 valueProperty: ‘code’, 17 values: supportedLanguages, 18 moduleName: ‘attachment’ 19 } 20 }; 21 22 constructor() { 23 super(‘UserForm’, ‘user’); 24 } 25 }

Slide 26

Slide 26

Speeding up form development @whereischarly 1 class Form extends ModuleForm { 2 fields: FieldsDefinitions = { 3 id: ‘none’, 4 email: ‘none’, 5 picture_path: { 6 type: ‘image’, transformations: ‘h_200,w_200,r_max,c_fill’ 7 }, 8 first_name: ‘string*’, 9 last_name: ‘string*’, 10 username: ‘string*’, 11 job_title: ‘string’, 12 company_name: ‘string’, 13 language: { 14 type: ‘select*’, 15 component: LanguageSelectView, 16 valueProperty: ‘code’, 17 values: supportedLanguages, 18 moduleName: ‘attachment’ 19 } 20 }; 21 22 constructor() { 23 super(‘UserForm’, ‘user’); 24 } 25 }

Slide 27

Slide 27

Speeding up form development @whereischarly

Slide 28

Slide 28

Speeding up form development @whereischarly

Slide 29

Slide 29

Speeding up form development Not the proper solution @whereischarly

Slide 30

Slide 30

Speeding up form development Not the proper solution Too many abstractions @whereischarly

Slide 31

Slide 31

Speeding up form development Not the proper solution Too many abstractions Not flexible @whereischarly

Slide 32

Slide 32

Speeding up form development Not the proper solution Too many abstractions Not flexible Not the “React way” @whereischarly

Slide 33

Slide 33

Leveraging GraphQL to improve form development @whereischarly

Slide 34

Slide 34

What is GraphQL? SPA @whereischarly HTTP requests GraphQL API

Slide 35

Slide 35

What is GraphQL? GraphQL API @whereischarly

Slide 36

Slide 36

What is GraphQL? GraphQL API GraphQL Schema @whereischarly

Slide 37

Slide 37

What is GraphQL? GraphQL API GraphQL Schema Data types @whereischarly

Slide 38

Slide 38

What is GraphQL? GraphQL API GraphQL Schema Data types @whereischarly Queries

Slide 39

Slide 39

What is GraphQL? GraphQL API GraphQL Schema Data types @whereischarly Queries Mutations

Slide 40

Slide 40

How to leverage GraphQL? GraphQL mutation design 1 mutation(user: UserInputType!, company: CompanyInputType) { 2 create_account(user: $user, company: $company) { 3 user { 4 id 5 } 6 } 7 } @whereischarly

Slide 41

Slide 41

How to leverage GraphQL? GraphQL mutation design 1 mutation(user: UserInputType!, company: CompanyInputType) { 2 create_account(user: $user, company: $company) { 3 user { 4 id 5 } 6 } 7 } @whereischarly

Slide 42

Slide 42

How to leverage GraphQL? 1. GraphQL mutations are based on business logic Onboarding Form mutation User model GraphQL API Company model @whereischarly

Slide 43

Slide 43

How to leverage GraphQL? 2. GraphQL introspection @whereischarly

Slide 44

Slide 44

How to leverage GraphQL? 2. GraphQL introspection introspection query @whereischarly

Slide 45

Slide 45

How to leverage GraphQL? 2. GraphQL introspection introspection query @whereischarly GraphQL API

Slide 46

Slide 46

How to leverage GraphQL? 2. GraphQL introspection introspection query @whereischarly GraphQL API 1 { 2 “name”: “createAccount”, 3 “__typename”: “__Field”, 4 “isDeprecated”: false, 5 “deprecationReason”: null, 6 “args”: [ 7 { 8 “name”: “user”, 9 “type”: { 10 “kind”: “NON_NULL”, 11 “name”: null, 12 “ofType”: { 13 “kind”: “InputType”, 14 “name”: “UserInputType”, 15 “ofType”: null, 16 “__typename”: “__Type” 17 }, 18 “__typename”: “__Type” 19 }, 20 “defaultValue”: null, 21 “__typename”: “__InputValue” 22 }, 23 // … 24 }

Slide 47

Slide 47

How to leverage GraphQL? 2. GraphQL introspection introspection query @whereischarly GraphQL API 1 { 2 “name”: “createAccount”, 3 “__typename”: “__Field”, 4 “isDeprecated”: false, 5 “deprecationReason”: null, 6 “args”: [ 7 { 8 “name”: “user”, 9 “type”: { 10 “kind”: “NON_NULL”, 11 “name”: null, 12 “ofType”: { 13 “kind”: “InputType”, 14 “name”: “UserInputType”, 15 “ofType”: null, 16 “__typename”: “__Type” 17 }, 18 “__typename”: “__Type” 19 }, 20 “defaultValue”: null, 21 “__typename”: “__InputValue” 22 }, 23 // … 24 }

Slide 48

Slide 48

How to leverage GraphQL? 2. GraphQL introspection introspection query @whereischarly GraphQL API 1 { 2 “name”: “createAccount”, 3 “__typename”: “__Field”, 4 “isDeprecated”: false, 5 “deprecationReason”: null, 6 “args”: [ 7 { 8 “name”: “user”, 9 “type”: { 10 “kind”: “NON_NULL”, 11 “name”: null, 12 “ofType”: { 13 “kind”: “InputType”, 14 “name”: “UserInputType”, 15 “ofType”: null, 16 “__typename”: “__Type” 17 }, 18 “__typename”: “__Type” 19 }, 20 “defaultValue”: null, 21 “__typename”: “__InputValue” 22 }, 23 // … 24 }

Slide 49

Slide 49

How to leverage GraphQL? 2. GraphQL introspection introspection query @whereischarly GraphQL API 1 { 2 “name”: “createAccount”, 3 “__typename”: “__Field”, 4 “isDeprecated”: false, 5 “deprecationReason”: null, 6 “args”: [ 7 { 8 “name”: “user”, 9 “type”: { 10 “kind”: “NON_NULL”, 11 “name”: null, 12 “ofType”: { 13 “kind”: “InputType”, 14 “name”: “UserInputType”, 15 “ofType”: null, 16 “__typename”: “__Type” 17 }, 18 “__typename”: “__Type” 19 }, 20 “defaultValue”: null, 21 “__typename”: “__InputValue” 22 }, 23 // … 24 }

Slide 50

Slide 50

How to leverage GraphQL? 2. GraphQL introspection introspection query @whereischarly GraphQL API “ You can create an Account by providing a mandatory User type and an optional Company type

Slide 51

Slide 51

GraphQL for forms @whereischarly

Slide 52

Slide 52

GraphQL for forms Mutation @whereischarly

Slide 53

Slide 53

GraphQL for forms Mutation @whereischarly = similar to Form UI

Slide 54

Slide 54

GraphQL for forms Mutation = similar to Form UI Mutation name

@whereischarly

Slide 55

Slide 55

GraphQL for forms Mutation = similar to Form UI Mutation name = fields + requirements @whereischarly

Slide 56

Slide 56

GraphQL for forms @whereischarly

Slide 57

Slide 57

<Frontier /> @wittydeveloper @chmelevskij

Slide 58

Slide 58

<Frontier /> Simplicity @whereischarly

Slide 59

Slide 59

Frontier forms Simplicity 1 <Frontier mutation={mutation} client={client} initialValues={{ user: { email: ‘hello@charlypoly.com ’ } }}> 2 { 3 ({ state, modifiers, form }) => { 4 return ( 5 <form onSubmit={modifiers.save}> 6 <h2>Create a user</h2> 7 <p> 8 <label htmlFor=”name”>Name*</label> <br /> 9 <input 10 type=”text” 11 name=”name” 12 value={state.values.user.name} onChange={modifiers.user.name.change} 13 /> 14 { 15 state.errors.user && state.errors.user.name && 16 <p> 17 Error: “{state.errors.user.name}” 18 </p> 19 } 20 </p> 21 <p> 22 <input type=”submit” value=”Save” /> 23 </p> 24 </form> 25 ) 26 } 27 } 28 </Frontier> @whereischarly

Slide 60

Slide 60

Frontier forms Simplicity 1 <Frontier mutation={mutation} client={client} initialValues={{ user: { email: ‘hello@charlypoly.com ’ } }}> 2 { 3 ({ state, modifiers, form }) => { 4 return ( 5 <form onSubmit={modifiers.save}> 6 <h2>Create a user</h2> 7 <p> 8 <label htmlFor=”name”>Name*</label> <br /> 9 <input 10 type=”text” 11 name=”name” 12 value={state.values.user.name} onChange={modifiers.user.name.change} 13 /> 14 { 15 state.errors.user && state.errors.user.name && 16 <p> 17 Error: “{state.errors.user.name}” 18 </p> 19 } 20 </p> 21 <p> 22 <input type=”submit” value=”Save” /> 23 </p> 24 </form> 25 ) 26 } 27 } 28 </Frontier> @whereischarly

Slide 61

Slide 61

Frontier forms Simplicity 1 <Frontier mutation={mutation} client={client} initialValues={{ user: { email: ‘hello@charlypoly.com ’ } }}> 2 { 3 ({ state, modifiers, form }) => { 4 return ( 5 <form onSubmit={modifiers.save}> 6 <h2>Create a user</h2> 7 <p> 8 <label htmlFor=”name”>Name*</label> <br /> 9 <input 10 type=”text” 11 name=”name” 12 value={state.values.user.name} onChange={modifiers.user.name.change} 13 /> 14 { 15 state.errors.user && state.errors.user.name && 16 <p> 17 Error: “{state.errors.user.name}” 18 </p> 19 } 20 </p> 21 <p> 22 <input type=”submit” value=”Save” /> 23 </p> 24 </form> 25 ) 26 } 27 } 28 </Frontier> @whereischarly

Slide 62

Slide 62

Frontier forms Simplicity 1 <Frontier mutation={mutation} client={client} initialValues={{ user: { email: ‘hello@charlypoly.com ’ } }}> 2 { 3 ({ state, modifiers, form }) => { 4 return ( 5 <form onSubmit={modifiers.save}> 6 <h2>Create a user</h2> 7 <p> 8 <label htmlFor=”name”>Name*</label> <br /> 9 <input 10 type=”text” 11 name=”name” 12 value={state.values.user.name} onChange={modifiers.user.name.change} 13 /> 14 { 15 state.errors.user && state.errors.user.name && 16 <p> 17 Error: “{state.errors.user.name}” 18 </p> 19 } 20 </p> 21 <p> 22 <input type=”submit” value=”Save” /> 23 </p> 24 </form> 25 ) 26 } 27 } 28 </Frontier> @whereischarly

Slide 63

Slide 63

Frontier forms Simplicity 1 <Frontier mutation={mutation} client={client} initialValues={{ user: { email: ‘hello@charlypoly.com ’ } }}> 2 { 3 ({ state, modifiers, form }) => { 4 return ( 5 <form onSubmit={modifiers.save}> 6 <h2>Create a user</h2> 7 <p> 8 <label htmlFor=”name”>Name*</label> <br /> 9 <input 10 type=”text” 11 name=”name” 12 value={state.values.user.name} onChange={modifiers.user.name.change} 13 /> 14 { 15 state.errors.user && state.errors.user.name && 16 <p> 17 Error: “{state.errors.user.name}” 18 </p> 19 } 20 </p> 21 <p> 22 <input type=”submit” value=”Save” /> 23 </p> 24 </form> 25 ) 26 } 27 } 28 </Frontier> @whereischarly

Slide 64

Slide 64

<Frontier /> Full data lifecycle management @whereischarly

Slide 65

Slide 65

Frontier forms @whereischarly Full-data lifecycle management

Slide 66

Slide 66

Frontier forms Fields definitions @whereischarly Full-data lifecycle management

Slide 67

Slide 67

Frontier forms Fields definitions @whereischarly Full-data lifecycle management Form state

Slide 68

Slide 68

Frontier forms Fields definitions @whereischarly Full-data lifecycle management Form state Save data

Slide 69

Slide 69

Frontier forms Fields definitions GraphQL @whereischarly Full-data lifecycle management Form state Save data

Slide 70

Slide 70

Frontier forms Full-data lifecycle management Fields definitions Form state GraphQL final-form @whereischarly Save data

Slide 71

Slide 71

Frontier forms Full-data lifecycle management Fields definitions Form state Save data GraphQL final-form Apollo GraphQL @whereischarly

Slide 72

Slide 72

<Frontier /> UI-Kit @whereischarly

Slide 73

Slide 73

Frontier forms UI-Kit 1 const mutation = gql2 mutation ($user: UserInputType!) { 3 createUser(user: $user) { 4 ...User 5 } 6 } 7; 8 9 <Frontier mutation={mutation} client={client} uiKit={ApplicationUIkit} /> @whereischarly

Slide 74

Slide 74

Frontier forms UI-Kit 1 const mutation = gql2 mutation ($user: UserInputType!) { 3 createUser(user: $user) { 4 ...User 5 } 6 } 7; 8 9 <Frontier mutation={mutation} client={client} uiKit={ApplicationUIkit} /> @whereischarly

Slide 75

Slide 75

Frontier forms UI-Kit 1 const mutation = gql2 mutation ($user: UserInputType!) { 3 createUser(user: $user) { 4 ...User 5 } 6 } 7; 8 9 <Frontier mutation={mutation} client={client} uiKit={ApplicationUIkit} /> @whereischarly

Slide 76

Slide 76

Frontier forms UI-Kit 1 const mutation = gql2 mutation ($user: UserInputType!) { 3 createUser(user: $user) { 4 ...User 5 } 6 } 7; 8 9 <Frontier mutation={mutation} client={client} uiKit={ApplicationUIkit} /> @whereischarly

Slide 77

Slide 77

Frontier forms @whereischarly UI-Kit

Slide 78

Slide 78

<Frontier /> Flexible @whereischarly

Slide 79

Slide 79

Frontier forms Flexible 1 <Frontier client={client} mutation={mutation} uiKit={ApplicationUIkit}> 2 { 3 ({ form, kit }) => { 4 return ( 5 <form className=’ui form’ onSubmit={(e) => { e.preventDefault(); form.submit(); }}> 6 <div> 7 {kit.company()} 8 </div> 9 <Message 10 info 11 header=’Is my company already registered?’ 12 list={[ 13 ‘If your company is already registred under a Business plan, please do register using the Business form’, 14 ]} 15 /> 16 <br /> 17 <br /> 18 <div> 19 {kit.email()} 20 </div> 21 <br /> 22 <div> 23 {kit.firstname()} 24 </div> 25 <br /> 26 <div> 27 {kit.lastname()} 28 </div> 29 <p> 30 <input type=”submit” value=”Save” className=”ui button” /> 31 </p> 32 </form> 33 ) 34 } 35 } 36 </Frontier>

Slide 80

Slide 80

Frontier forms Flexible 1 <Frontier client={client} mutation={mutation} uiKit={ApplicationUIkit}> 2 { 3 ({ form, kit }) => { 4 return ( 5 <form className=’ui form’ onSubmit={(e) => { e.preventDefault(); form.submit(); }}> 6 <div> 7 {kit.company()} 8 </div> 9 <Message 10 info 11 header=’Is my company already registered?’ 12 list={[ 13 ‘If your company is already registred under a Business plan, please do register using the Business form’, 14 ]} 15 /> 16 <br /> 17 <br /> 18 <div> 19 {kit.email()} 20 </div> 21 <br /> 22 <div> 23 {kit.firstname()} 24 </div> 25 <br /> 26 <div> 27 {kit.lastname()} 28 </div> 29 <p> 30 <input type=”submit” value=”Save” className=”ui button” /> 31 </p> 32 </form> 33 ) 34 } 35 } 36 </Frontier>

Slide 81

Slide 81

Frontier forms Flexible 1 <Frontier client={client} mutation={mutation} uiKit={ApplicationUIkit}> 2 { 3 ({ form, kit }) => { 4 return ( 5 <form className=’ui form’ onSubmit={(e) => { e.preventDefault(); form.submit(); }}> 6 <div> 7 {kit.company()} 8 </div> 9 <Message 10 info 11 header=’Is my company already registered?’ 12 list={[ 13 ‘If your company is already registred under a Business plan, please do register using the Business form’, 14 ]} 15 /> 16 <br /> 17 <br /> 18 <div> 19 {kit.email()} 20 </div> 21 <br /> 22 <div> 23 {kit.firstname()} 24 </div> 25 <br /> 26 <div> 27 {kit.lastname()} 28 </div> 29 <p> 30 <input type=”submit” value=”Save” className=”ui button” /> 31 </p> 32 </form> 33 ) 34 } 35 } 36 </Frontier>

Slide 82

Slide 82

Frontier forms Flexible 1 <Frontier client={client} mutation={mutation} uiKit={ApplicationUIkit}> 2 { 3 ({ form, kit }) => { 4 return ( 5 <form className=’ui form’ onSubmit={(e) => { e.preventDefault(); form.submit(); }}> 6 <div> 7 {kit.company()} 8 </div> 9 <Message 10 info 11 header=’Is my company already registered?’ 12 list={[ 13 ‘If your company is already registred under a Business plan, please do register using the Business form’, 14 ]} 15 /> 16 <br /> 17 <br /> 18 <div> 19 {kit.email()} 20 </div> 21 <br /> 22 <div> 23 {kit.firstname()} 24 </div> 25 <br /> 26 <div> 27 {kit.lastname()} 28 </div> 29 <p> 30 <input type=”submit” value=”Save” className=”ui button” /> 31 </p> 32 </form> 33 ) 34 } 35 } 36 </Frontier>

Slide 83

Slide 83

Frontier forms Flexible 1 <Frontier client={client} mutation={mutation} uiKit={ApplicationUIkit}> 2 { 3 ({ form, kit }) => { 4 return ( 5 <form className=’ui form’ onSubmit={(e) => { e.preventDefault(); form.submit(); }}> 6 <div> 7 {kit.company()} 8 </div> 9 <Message 10 info 11 header=’Is my company already registered?’ 12 list={[ 13 ‘If your company is already registred under a Business plan, please do register using the Business form’, 14 ]} 15 /> 16 <br /> 17 <br /> 18 <div> 19 {kit.email()} 20 </div> 21 <br /> 22 <div> 23 {kit.firstname()} 24 </div> 25 <br /> 26 <div> 27 {kit.lastname()} 28 </div> 29 <p> 30 <input type=”submit” value=”Save” className=”ui button” /> 31 </p> 32 </form> 33 ) 34 } 35 } 36 </Frontier>

Slide 84

Slide 84

Frontier forms Flexible 1 <Frontier client={client} mutation={mutation} uiKit={ApplicationUIkit}> 2 { 3 ({ form, kit }) => { 4 return ( 5 <form className=’ui form’ onSubmit={(e) => { e.preventDefault(); form.submit(); }}> 6 <div> 7 {kit.company()} 8 </div> 9 <Message 10 info 11 header=’Is my company already registered?’ 12 list={[ 13 ‘If your company is already registred under a Business plan, please do register using the Business form’, 14 ]} 15 /> 16 <br /> 17 <br /> 18 <div> 19 {kit.email()} 20 </div> 21 <br /> 22 <div> 23 {kit.firstname()} 24 </div> 25 <br /> 26 <div> 27 {kit.lastname()} 28 </div> 29 <p> 30 <input type=”submit” value=”Save” className=”ui button” /> 31 </p> 32 </form> 33 ) 34 } 35 } 36 </Frontier>

Slide 85

Slide 85

Frontier forms Flexible

Slide 86

Slide 86

Frontier forms A new form development experience @whereischarly

Slide 87

Slide 87

Frontier forms A new form development experience Full data lifecycle management: state, validation, save @whereischarly

Slide 88

Slide 88

Frontier forms A new form development experience Full data lifecycle management: state, validation, save UI-kit full rendering: bring a consistent experience to your users @whereischarly

Slide 89

Slide 89

Frontier forms A new form development experience Full data lifecycle management: state, validation, save UI-kit full rendering: bring a consistent experience to your users Simple and iterative: choose your form development flow @whereischarly

Slide 90

Slide 90

Frontier forms: demos How to: Define and use a UI-Kit for your application Advanced use-cases (validations & complex types) https://codesandbox.io/s/7j3xo3qy26 @whereischarly

Slide 91

Slide 91

Frontier: built for the future @whereischarly

Slide 92

Slide 92

Frontier: built for the future Frontier Data @whereischarly

Slide 93

Slide 93

Frontier: built for the future Frontier Data - Apollo GraphQL @whereischarly

Slide 94

Slide 94

Frontier: built for the future Frontier Data - Apollo GraphQL @whereischarly Frontier Core

Slide 95

Slide 95

Frontier: built for the future Frontier Data - Apollo GraphQL @whereischarly Frontier Core - ajv - final-form

Slide 96

Slide 96

Frontier: built for the future Frontier Data - Apollo GraphQL @whereischarly Frontier Core - ajv - final-form Frontier React

Slide 97

Slide 97

Frontier: built for the future @whereischarly

Slide 98

Slide 98

Frontier: built for the future Swagger support @whereischarly

Slide 99

Slide 99

Frontier: built for the future Swagger support More flavours: Vue.js, Angular and React Native @whereischarly

Slide 100

Slide 100

Frontier: built for the future Swagger support More flavours: Vue.js, Angular and React Native API improvements @whereischarly

Slide 101

Slide 101

frontier-forms.dev 👀

Slide 102

Slide 102

🔗 We are hiring! honest.engineering @whereischarly /wittydeveloper

Slide 103

Slide 103

🔗 We are hiring! honest.engineering @whereischarly Thank you! /wittydeveloper