or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-widgets.mdcomponents.mdforms.mdicons.mdindex.mdtoolbars.mdutilities.mdwidgets.md
tile.json

forms.mddocs/

0

# Form System

1

2

Advanced form rendering capabilities using React JSON Schema Form (RJSF) with JupyterLab-specific customizations. The form system provides dynamic form generation, validation, and custom field rendering with full TypeScript support.

3

4

## Capabilities

5

6

### FormComponent

7

8

Generic RJSF form component with JupyterLab customizations and styling.

9

10

```typescript { .api }

11

/**

12

* Generic RJSF form component with JupyterLab styling and customizations

13

*/

14

interface IFormComponentProps<T = ReadonlyJSONObject> extends FormProps<T>, FormComponent.ILabCustomizerProps {

15

/** Current form data */

16

formData: T;

17

/** Callback for form data changes */

18

onChange: (e: IChangeEvent<T>) => any;

19

/** Additional form context */

20

formContext?: unknown;

21

}

22

23

/**

24

* Main form component for rendering JSON Schema forms

25

* @param props - Form configuration and data

26

* @returns JSX form element

27

*/

28

function FormComponent(props: IFormComponentProps): JSX.Element;

29

30

namespace FormComponent {

31

interface IButtonProps {

32

/** Button style variant for array controls */

33

buttonStyle?: 'icons' | 'text';

34

/** Translator for internationalization */

35

translator?: ITranslator;

36

}

37

38

interface ILabCustomizerProps extends IButtonProps {

39

/** Use compact form layout */

40

compact?: boolean;

41

/** Show indicators for values that differ from defaults */

42

showModifiedFromDefault?: boolean;

43

}

44

}

45

46

/**

47

* Default UI options for forms

48

*/

49

const DEFAULT_UI_OPTIONS = {

50

submitButtonOptions: { norender: true }

51

};

52

```

53

54

**Usage Examples:**

55

56

```typescript

57

import React, { useState } from 'react';

58

import { FormComponent, DEFAULT_UI_OPTIONS } from '@jupyterlab/ui-components';

59

import { JSONSchema7 } from 'json-schema';

60

61

// Basic form usage

62

interface UserSettings {

63

theme: string;

64

fontSize: number;

65

enableAutoSave: boolean;

66

}

67

68

const userSchema: JSONSchema7 = {

69

type: 'object',

70

properties: {

71

theme: {

72

type: 'string',

73

enum: ['light', 'dark', 'auto'],

74

default: 'light'

75

},

76

fontSize: {

77

type: 'number',

78

minimum: 10,

79

maximum: 24,

80

default: 14

81

},

82

enableAutoSave: {

83

type: 'boolean',

84

default: true

85

}

86

}

87

};

88

89

function SettingsForm() {

90

const [formData, setFormData] = useState<UserSettings>({

91

theme: 'light',

92

fontSize: 14,

93

enableAutoSave: true

94

});

95

96

return (

97

<FormComponent

98

schema={userSchema}

99

formData={formData}

100

onChange={(e) => setFormData(e.formData)}

101

uiSchema={{

102

...DEFAULT_UI_OPTIONS,

103

theme: { 'ui:widget': 'select' },

104

fontSize: { 'ui:widget': 'range' }

105

}}

106

compact={true}

107

showModifiedFromDefault={true}

108

/>

109

);

110

}

111

112

// Advanced form with custom widgets

113

const advancedSchema: JSONSchema7 = {

114

type: 'object',

115

properties: {

116

plugins: {

117

type: 'array',

118

items: {

119

type: 'object',

120

properties: {

121

name: { type: 'string' },

122

enabled: { type: 'boolean' },

123

config: { type: 'object' }

124

}

125

}

126

}

127

}

128

};

129

130

function AdvancedForm() {

131

const [data, setData] = useState({ plugins: [] });

132

133

return (

134

<FormComponent

135

schema={advancedSchema}

136

formData={data}

137

onChange={(e) => setData(e.formData)}

138

buttonStyle="icons"

139

uiSchema={{

140

plugins: {

141

'ui:options': {

142

addable: true,

143

removable: true

144

}

145

}

146

}}

147

/>

148

);

149

}

150

```

151

152

### Array Control Buttons

153

154

Specialized buttons for managing array items in forms.

155

156

```typescript { .api }

157

/**

158

* Button for moving array items up/down

159

* @param props - Button styling properties

160

* @returns JSX button element

161

*/

162

function MoveButton(props: FormComponent.IButtonProps): JSX.Element;

163

164

/**

165

* Button for removing array items

166

* @param props - Button styling properties

167

* @returns JSX button element

168

*/

169

function DropButton(props: FormComponent.IButtonProps): JSX.Element;

170

171

/**

172

* Button for adding new array items

173

* @param props - Button styling properties

174

* @returns JSX button element

175

*/

176

function AddButton(props: FormComponent.IButtonProps): JSX.Element;

177

```

178

179

**Usage Examples:**

180

181

```typescript

182

import { MoveButton, DropButton, AddButton } from '@jupyterlab/ui-components';

183

184

// Custom array template with styled buttons

185

function CustomArrayTemplate(props: any) {

186

return (

187

<div className="array-container">

188

<div className="array-header">

189

<h3>{props.title}</h3>

190

<AddButton buttonStyle="icons" />

191

</div>

192

193

{props.items.map((element: any, index: number) => (

194

<div key={index} className="array-item">

195

<div className="item-content">

196

{element.children}

197

</div>

198

<div className="item-controls">

199

<MoveButton buttonStyle="icons" />

200

<DropButton buttonStyle="text" />

201

</div>

202

</div>

203

))}

204

</div>

205

);

206

}

207

208

// Use in form configuration

209

const arrayFormConfig = {

210

schema: myArraySchema,

211

uiSchema: {

212

myArray: {

213

'ui:ArrayFieldTemplate': CustomArrayTemplate

214

}

215

}

216

};

217

```

218

219

### Form Renderer Registry

220

221

Registry system for custom form field and widget renderers.

222

223

```typescript { .api }

224

/**

225

* Interface for form renderers

226

*/

227

interface IFormRenderer {

228

/** Custom field renderer */

229

fieldRenderer?: Field;

230

/** Custom widget renderer */

231

widgetRenderer?: Widget;

232

}

233

234

/**

235

* Registry interface for managing form renderers

236

*/

237

interface IFormRendererRegistry {

238

/** Add a new renderer to the registry */

239

addRenderer: (id: string, renderer: IFormRenderer) => void;

240

/** Get renderer by ID */

241

getRenderer: (id: string) => IFormRenderer;

242

/** All registered renderers */

243

renderers: { [id: string]: IFormRenderer };

244

}

245

246

/**

247

* Dependency injection token for form renderer registry

248

*/

249

const IFormRendererRegistry: Token<IFormRendererRegistry>;

250

251

/**

252

* Concrete implementation of form renderer registry

253

*/

254

class FormRendererRegistry implements IFormRendererRegistry {

255

addRenderer(id: string, renderer: IFormRenderer): void;

256

getRenderer(id: string): IFormRenderer;

257

get renderers(): { [id: string]: IFormRenderer };

258

}

259

260

/**

261

* Placeholder interface for future icon manager functionality

262

*/

263

interface ILabIconManager {}

264

265

/**

266

* Dependency injection token for icon manager service

267

*/

268

const ILabIconManager: Token<ILabIconManager>;

269

```

270

271

**Usage Examples:**

272

273

```typescript

274

import { FormRendererRegistry, IFormRenderer } from '@jupyterlab/ui-components';

275

276

// Create custom renderer

277

const colorPickerRenderer: IFormRenderer = {

278

widgetRenderer: ({ value, onChange }) => (

279

<input

280

type="color"

281

value={value || '#000000'}

282

onChange={(e) => onChange(e.target.value)}

283

className="color-picker-widget"

284

/>

285

)

286

};

287

288

// Register custom renderer

289

const registry = new FormRendererRegistry();

290

registry.addRenderer('colorPicker', colorPickerRenderer);

291

292

// Use in form schema

293

const schemaWithCustomWidget: JSONSchema7 = {

294

type: 'object',

295

properties: {

296

backgroundColor: {

297

type: 'string',

298

format: 'color',

299

default: '#ffffff'

300

}

301

}

302

};

303

304

const uiSchemaWithCustomWidget = {

305

backgroundColor: {

306

'ui:widget': 'colorPicker'

307

}

308

};

309

310

// Register with dependency injection

311

import { ServiceManager } from '@jupyterlab/services';

312

313

const services = new ServiceManager();

314

services.contents.add(IFormRendererRegistry, new FormRendererRegistry());

315

316

// Get registered renderer

317

const renderer = registry.getRenderer('colorPicker');

318

```

319

320

### Form Validation and Error Handling

321

322

Built-in validation and error display capabilities.

323

324

```typescript { .api }

325

// Form validation is handled through JSON Schema validation

326

// Custom validation can be added through schema definitions

327

328

interface ValidationError {

329

name: string;

330

property: string;

331

message: string;

332

argument: any;

333

stack: string;

334

}

335

336

// Error handling in form components

337

interface FormErrorProps {

338

errors: ValidationError[];

339

schema: JSONSchema7;

340

uiSchema: any;

341

}

342

```

343

344

**Usage Examples:**

345

346

```typescript

347

import { FormComponent } from '@jupyterlab/ui-components';

348

import { JSONSchema7 } from 'json-schema';

349

350

// Schema with validation rules

351

const validationSchema: JSONSchema7 = {

352

type: 'object',

353

properties: {

354

email: {

355

type: 'string',

356

format: 'email',

357

title: 'Email Address'

358

},

359

age: {

360

type: 'number',

361

minimum: 0,

362

maximum: 150,

363

title: 'Age'

364

},

365

password: {

366

type: 'string',

367

minLength: 8,

368

pattern: '^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)',

369

title: 'Password'

370

}

371

},

372

required: ['email', 'password']

373

};

374

375

// Custom validation function

376

function customValidate(formData: any, errors: any) {

377

if (formData.password && formData.confirmPassword) {

378

if (formData.password !== formData.confirmPassword) {

379

errors.confirmPassword.addError('Passwords must match');

380

}

381

}

382

return errors;

383

}

384

385

// Form with validation

386

function ValidatedForm() {

387

const [formData, setFormData] = useState({});

388

const [errors, setErrors] = useState<ValidationError[]>([]);

389

390

return (

391

<div>

392

<FormComponent

393

schema={validationSchema}

394

formData={formData}

395

onChange={(e) => {

396

setFormData(e.formData);

397

setErrors(e.errors || []);

398

}}

399

validate={customValidate}

400

showErrorList={true}

401

liveValidate={true}

402

/>

403

404

{errors.length > 0 && (

405

<div className="form-errors">

406

<h4>Please fix the following errors:</h4>

407

<ul>

408

{errors.map((error, i) => (

409

<li key={i}>{error.message}</li>

410

))}

411

</ul>

412

</div>

413

)}

414

</div>

415

);

416

}

417

```

418

419

### Custom Field Templates

420

421

Create custom templates for specific form fields and layouts.

422

423

```typescript { .api }

424

// Custom field template interfaces from RJSF

425

interface FieldTemplateProps {

426

id: string;

427

label: string;

428

children: React.ReactNode;

429

errors: React.ReactNode;

430

help: React.ReactNode;

431

description: React.ReactNode;

432

hidden: boolean;

433

required: boolean;

434

readonly: boolean;

435

disabled: boolean;

436

displayLabel: boolean;

437

schema: JSONSchema7;

438

uiSchema: any;

439

formContext: any;

440

}

441

```

442

443

**Usage Examples:**

444

445

```typescript

446

import { FormComponent } from '@jupyterlab/ui-components';

447

448

// Custom field template

449

function CustomFieldTemplate(props: FieldTemplateProps) {

450

const { id, label, children, errors, help, required, schema } = props;

451

452

return (

453

<div className={`field-${schema.type}`}>

454

<div className="field-header">

455

<label htmlFor={id} className="field-label">

456

{label}

457

{required && <span className="required">*</span>}

458

</label>

459

{help && <div className="field-help">{help}</div>}

460

</div>

461

462

<div className="field-input">

463

{children}

464

</div>

465

466

{errors && <div className="field-errors">{errors}</div>}

467

</div>

468

);

469

}

470

471

// Use custom template in form

472

<FormComponent

473

schema={mySchema}

474

formData={formData}

475

onChange={handleChange}

476

templates={{

477

FieldTemplate: CustomFieldTemplate

478

}}

479

/>

480

481

// Custom object field template

482

function CustomObjectTemplate(props: any) {

483

return (

484

<fieldset className="object-fieldset">

485

<legend>{props.title}</legend>

486

<div className="object-properties">

487

{props.properties.map((prop: any) => prop.content)}

488

</div>

489

</fieldset>

490

);

491

}

492

493

// Apply to specific fields

494

const customUiSchema = {

495

myObject: {

496

'ui:ObjectFieldTemplate': CustomObjectTemplate

497

}

498

};

499

```