Skip to main content
Praktikum 1·
13 September 2026

Input Widget dan Basic Form

REPOSITORY_GITHUB

Praktikum ini membahas Input Widgets dan Basic Form pada Flutter. Tujuannya membuat form yang bisa menerima inputan dari keyboard lalu memvalidasi dan mengelola inputan tersebut.

ITujuan Praktikum

Setelah menyelesaikan praktikum ini, mahasiswa diharapkan mampu:

  • mampu membuat membuat basic form untuk menerima inputan dari keyboard dan mengelola inputan
  • Membuat beberapa input widgets
  • Membuat dan mengontrol inputan dari user

IIDasar Teori

Basic Form


Basic Form merupakan widget yang berfungsi sebagai inputan nilai seperti TextField, TextFormField,

CheckBox, Switch, Dropdown, Radio, Dialog, DatePicker, BottomSheet, Snackbar dan lain-lain. Basic

Form digunakan untuk validasi dan mengelola inputan dari berbagai field.

Form akan memberikan tampilan inputan kemudian inputan akan diperiksa apakah sudah sesuai

dengan aturan atau format yang ditetapkan, selanjtunya data inputan akan diambil nilainya setelah

proses pengecekan selesai dilakukan.

TextField


TextField adalah widget yang digunakan untuk memasukkan text oleh pengguna, widget ini biasanya
digunakan untuk membuat form inputan seperti form login, pencarian dll.

Fitur TextField:

  • Menerima input dari keyboard

  • Memiliki property yang lengkap style, decoration, dan jenis inputan

  • Dapat mengelola teks menggunakan TextEditingController

IIIAlat dan Bahan

Komputer / laptop yang telah terinstall lingkungan Flutter development

IVLangkah Kerja Praktikum

1

Basic Form TextField

1.1 Buat file dart baru dengan nama form-textfield.dart di dalam folder lib.

1.2 Buat tampilan basic form menggunakan widget TextField untuk inputan dan ElevatedButton untuk memberikan event listener. Tuliskan kode program berikut:

dart
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Basic Form'),
        ),
        body: const MyForm(),
      ),
    );
  }
}

class MyForm extends StatefulWidget {
  const MyForm({super.key});

  @override
  State<MyForm> createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(20.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text('Masukkan nama anda :'),
          const SizedBox(
            height: 10,
          ),
          const TextField(
            decoration: InputDecoration(
                labelText: 'Nama Lengkap',
                hintText: 'Misalnya masnoer',
                border: OutlineInputBorder(),
                prefixIcon: Icon(Icons.person)),
          ),
          const SizedBox(
            height: 20,
          ),
          ElevatedButton(
              onPressed: () {},
              style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.amber, foregroundColor: Colors.black),
              child: const Text('Tampilkan mama'))
        ],
      ),
    );
  }
}

1.3 Pada class _MyFormState tambahkan kode program berikut:

dart
TextEditingController _textEditingController = TextEditingController();
@override
void dispose() {
  _textEditingController.dispose();
  super.dispose();
}

Penjelasan:

  • Baris pertama membuat variabel dari TextEditingController. Controller ini berfungsi untuk mengambil inputan dari user.

  • Method dispose() digunakan untuk membersihkan controller teks inputan ketika widget sudah tidak digunakan.

1.4 Tambahkan property controller, keyboardType, dan onChanged pada widget TextField:

dart
TextField(
  decoration: InputDecoration(
    labelText: 'Nama Lengkap',
    hintText: 'Misalnya masnoer',
    border: OutlineInputBorder(),
    prefixIcon: Icon(Icons.person),
  ),
  controller: _textEditingController,
  keyboardType: TextInputType.text,
  onChanged: (text) {
    print('Sedang mengetik teks: ,$text');
  },
),

Penjelasan:

  • controller: _textEditingController menghubungkan TextField dengan controller.

  • keyboardType: TextInputType.text menentukan jenis inputan yang boleh diinputkan oleh user.

  • onChanged merupakan event listener yang dijalankan ketika user sedang mengetikkan teks.

  • Kata kunci const pada TextField dihapus karena _textEditingController bukan nilai konstanta.

1.5 Tambahkan kode program berikut pada onPressed di widget ElevatedButton:

dart
onPressed: () {
  String inputText = _textEditingController.text;
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text('Nama anda adalah , $inputText')),
  );
},

Penjelasan:

  • Variabel inputText berfungsi untuk menampung inputan dari keyboard melalui _textEditingController.text.

  • ScaffoldMessenger.of(context).showSnackBar(...) menampilkan inputan teks menggunakan widget SnackBar.

1.6 Simpan kemudian RUN. Ketikkan nama pada TextField (teks yang sedang diketik akan tercetak di console), lalu tekan tombol Tampilkan mama, maka nama akan tampil pada SnackBar.

2

Basic Form TextFormField

2.1 Buat file baru di dalam folder lib dengan nama form-textformfield.dart.

2.2 Buat form inputan menggunakan 2 buah widget TextFormField dan 1 buah ElevatedButton. Tuliskan kode program berikut:

dart
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text("Basic Form TextFormField"),
        ),
        body: const MyFormText(),
      ),
    );
  }
}

class MyFormText extends StatefulWidget {
  const MyFormText({super.key});

  @override
  State<MyFormText> createState() => _MyFormTextState();
}

class _MyFormTextState extends State<MyFormText> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        const SizedBox(
          height: 10,
        ),
        TextFormField(
          decoration: const InputDecoration(
              labelText: "Nama : ", border: OutlineInputBorder()),
        ),
        const SizedBox(
          height: 10,
        ),
        TextFormField(
          decoration: const InputDecoration(
              labelText: "Email : ", border: OutlineInputBorder()),
        ),
        const SizedBox(
          height: 10,
        ),
        SizedBox(
            width: double.infinity,
            child:
                ElevatedButton(onPressed: () {}, child: const Text('Submit')))
      ],
    );
  }
}

2.3 Tambahkan pada class _MyFormTextState kode program berikut:

dart
final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController();
final _emailController = TextEditingController();

@override
void dispose() {
  _nameController.dispose();
  _emailController.dispose();
  super.dispose();
}

void _submitForm() {
  if (_formKey.currentState!.validate()) {
    String name = _nameController.text;
    String email = _emailController.text;

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Validasi $name, $email Berhasil')),
    );
  }
}

Penjelasan:

  • _formKey merupakan variabel GlobalKey<FormState> untuk mengakses state dari Form.

  • _nameController dan _emailController merupakan controller untuk TextFormField.

  • Method dispose() berfungsi untuk menghapus controller inputan name dan email.

  • Method _submitForm() digunakan ketika tombol diklik. _formKey.currentState!.validate() menjalankan semua validator; jika semua valid maka SnackBar ditampilkan.

2.4 Pada widget tampilan, bungkus menggunakan widget Form dan tambahkan key: _formKey. Tambahkan juga Padding agar form tidak menempel ke tepi layar:

dart
return Form(
  key: _formKey,
  child: Padding(
    padding: const EdgeInsets.all(20.0),
    child: Column(
      mainAxisAlignment: MainAxisAlignment.start,
      children: [
        // ... TextFormField dan ElevatedButton
      ],
    ),
  ),
);

2.5 Ubah kode program pada kedua TextFormField dengan menambahkan controller dan validator:

TextFormField Nama:

dart
TextFormField(
  controller: _nameController,
  decoration: const InputDecoration(
    labelText: "Nama : ",
    border: OutlineInputBorder(),
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Masukkan nama anda';
    }
    return null;
  },
),

TextFormField Email:

dart
TextFormField(
  controller: _emailController,
  decoration: const InputDecoration(
    labelText: "Email : ",
    border: OutlineInputBorder(),
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Masukkan email anda';
    }
    if (!value.contains('@')) {
      return 'Email tidak valid';
    }
    return null;
  },
),

Penjelasan:

  • Validator nama mengembalikan pesan error jika inputan kosong.

  • Validator email mengembalikan pesan error jika inputan kosong atau tidak mengandung karakter @.

  • Jika validator mengembalikan null, berarti inputan valid.

2.6 Tambahkan method _submitForm pada onPressed di ElevatedButton:

dart
SizedBox(
  width: double.infinity,
  child: ElevatedButton(
    onPressed: _submitForm,
    child: const Text('Submit'),
  ),
),

2.7 Simpan dan RUN. Tekan tombol Submit saat inputan kosong, maka pesan error akan muncul di bawah TextFormField. Isi nama dan email yang benar lalu tekan Submit, maka SnackBar "Validasi ... Berhasil" akan tampil.

VLatihan dan Tugas

1

Buat 2 buah file dart di dalam folder lib, yaitu main.dart dan user_registration_form.dart.

2

Pada file main.dart, gunakan MaterialApp sebagai root dan set property home ke widget UserRegistrationForm:

dart
import 'package:flutter/material.dart';
import 'user_registration_form.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: UserRegistrationForm(),
    );
  }
}

Penjelasan:

  • import 'user_registration_form.dart'; digunakan agar class UserRegistrationForm dari file lain dapat dipanggil di main.dart.

  • MaterialApp menjadi root aplikasi dan property home diisi dengan widget UserRegistrationForm.

3

Pada file user_registration_form.dart, buat class UserRegistrationForm menggunakan StatefulWidget:

dart
import 'package:flutter/material.dart';

class UserRegistrationForm extends StatefulWidget {
  const UserRegistrationForm({super.key});

  @override
  State<UserRegistrationForm> createState() => _UserRegistrationFormState();
}
4

Pada class _UserRegistrationFormState, buat variabel GlobalKey, 4 buah controller, dan method dispose():

dart
class _UserRegistrationFormState extends State<UserRegistrationForm> {
  final _formKey = GlobalKey<FormState>();
  final _nameController = TextEditingController();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _confirmPasswordController = TextEditingController();

  @override
  void dispose() {
    _nameController.dispose();
    _emailController.dispose();
    _passwordController.dispose();
    _confirmPasswordController.dispose();
    super.dispose();
  }

Penjelasan:

  • _formKey digunakan untuk mengakses FormState sehingga dapat memanggil method validate().

  • Masing-masing controller digunakan untuk mengambil nilai inputan nama, email, password, dan confirm password.

  • Method dispose() membersihkan semua controller ketika widget tidak digunakan lagi.

5

Buat method _submitForm() yang akan dipanggil ketika tombol Submit ditekan:

dart
  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      String name = _nameController.text;
      String email = _emailController.text;

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Pendaftaran $name, $email Berhasil')),
      );
    }
  }

Penjelasan:

  • _formKey.currentState!.validate() menjalankan validator pada seluruh TextFormField.

  • Jika semua inputan valid, nilai nama dan email diambil dari controller lalu ditampilkan melalui SnackBar.

6

Buat method build() yang mengembalikan Scaffold, lalu bungkus inputan menggunakan widget Form dengan key: _formKey:

dart
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Form Pendaftaran Pengguna')),
      body: Form(
        key: _formKey,
        child: Padding(
          padding: const EdgeInsets.all(20.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              // ... 4 TextFormField dan ElevatedButton
            ],
          ),
        ),
      ),
    );
  }

Penjelasan:

  • Karena property home pada MaterialApp langsung diisi UserRegistrationForm, maka Scaffold dan AppBar dibuat di dalam UserRegistrationForm.

7

Tambahkan TextFormField untuk inputan Nama dengan validator tidak boleh kosong:

dart
              const SizedBox(height: 10),
              TextFormField(
                controller: _nameController,
                decoration: const InputDecoration(
                  labelText: "Nama : ",
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.person),
                ),
                keyboardType: TextInputType.text,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Masukkan nama anda';
                  }
                  return null;
                },
              ),
8

Tambahkan TextFormField untuk inputan Email dengan validator harus menggunakan format @:

dart
              const SizedBox(height: 10),
              TextFormField(
                controller: _emailController,
                decoration: const InputDecoration(
                  labelText: "Email : ",
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.email),
                ),
                keyboardType: TextInputType.emailAddress,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Masukkan email anda';
                  }
                  if (!value.contains('@')) {
                    return 'Email tidak valid';
                  }
                  return null;
                },
              ),

Penjelasan:

  • !value.contains('@') bernilai true jika inputan email tidak mengandung karakter @, sehingga validator mengembalikan pesan 'Email tidak valid'.

9

Tambahkan TextFormField untuk inputan Password:

dart
              const SizedBox(height: 10),
              TextFormField(
                controller: _passwordController,
                decoration: const InputDecoration(
                  labelText: "Password : ",
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.lock),
                ),
                obscureText: true,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Masukkan password anda';
                  }
                  return null;
                },
              ),

Penjelasan:

  • obscureText: true digunakan agar teks password yang diketik disembunyikan.

10

Tambahkan TextFormField untuk inputan Confirm Password dengan validator harus sama dengan password:

dart
              const SizedBox(height: 10),
              TextFormField(
                controller: _confirmPasswordController,
                decoration: const InputDecoration(
                  labelText: "Confirm Password : ",
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.lock),
                ),
                obscureText: true,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Masukkan confirm password anda';
                  }
                  if (value != _passwordController.text) {
                    return 'Password dan confirm password tidak sama';
                  }
                  return null;
                },
              ),

Penjelasan:

  • value != _passwordController.text membandingkan inputan confirm password dengan inputan password. Jika tidak sama, validator mengembalikan pesan error.

11

Tambahkan ElevatedButton dengan onPressed yang memanggil _submitForm:

dart
              const SizedBox(height: 10),
              SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: _submitForm,
                  child: const Text('Submit'),
                ),
              ),
12

Simpan dan RUN file main.dart

#1 Kode program lengkap main.dart:

dart
import 'package:flutter/material.dart';
import 'user_registration_form.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: UserRegistrationForm(),
    );
  }
}

#2 Kode program lengkap user_registration_form.dart:

dart
import 'package:flutter/material.dart';

class UserRegistrationForm extends StatefulWidget {
  const UserRegistrationForm({super.key});

  @override
  State<UserRegistrationForm> createState() => _UserRegistrationFormState();
}

class _UserRegistrationFormState extends State<UserRegistrationForm> {
  final _formKey = GlobalKey<FormState>();
  final _nameController = TextEditingController();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _confirmPasswordController = TextEditingController();

  @override
  void dispose() {
    _nameController.dispose();
    _emailController.dispose();
    _passwordController.dispose();
    _confirmPasswordController.dispose();
    super.dispose();
  }

  void _submitForm() {
    if (_formKey.currentState!.validate()) {
      String name = _nameController.text;
      String email = _emailController.text;

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Pendaftaran $name, $email Berhasil')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Form Pendaftaran Pengguna')),
      body: Form(
        key: _formKey,
        child: Padding(
          padding: const EdgeInsets.all(20.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              const SizedBox(height: 10),
              TextFormField(
                controller: _nameController,
                decoration: const InputDecoration(
                  labelText: "Nama : ",
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.person),
                ),
                keyboardType: TextInputType.text,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Masukkan nama anda';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 10),
              TextFormField(
                controller: _emailController,
                decoration: const InputDecoration(
                  labelText: "Email : ",
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.email),
                ),
                keyboardType: TextInputType.emailAddress,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Masukkan email anda';
                  }
                  if (!value.contains('@')) {
                    return 'Email tidak valid';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 10),
              TextFormField(
                controller: _passwordController,
                decoration: const InputDecoration(
                  labelText: "Password : ",
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.lock),
                ),
                obscureText: true,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Masukkan password anda';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 10),
              TextFormField(
                controller: _confirmPasswordController,
                decoration: const InputDecoration(
                  labelText: "Confirm Password : ",
                  border: OutlineInputBorder(),
                  prefixIcon: Icon(Icons.lock),
                ),
                obscureText: true,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Masukkan confirm password anda';
                  }
                  if (value != _passwordController.text) {
                    return 'Password dan confirm password tidak sama';
                  }
                  return null;
                },
              ),
              const SizedBox(height: 10),
              SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  onPressed: _submitForm,
                  child: const Text('Submit'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

VIKesimpulan

  1. Basic Form pada Flutter merupakan kumpulan widget inputan (seperti TextField dan TextFormField) yang digunakan untuk menerima, memvalidasi, dan mengelola inputan dari user. Inputan diperiksa terlebih dahulu apakah sesuai aturan, kemudian nilainya diambil setelah proses pengecekan selesai.

  2. TextField digunakan untuk menerima input teks dari keyboard. Nilai inputannya dapat diambil menggunakan TextEditingController, dan perubahan teks dapat dipantau menggunakan event onChanged.

  3. TextFormField merupakan versi lengkap dari TextField yang terintegrasi dengan Form. Melalui property validator, inputan dapat diperiksa dan pesan error otomatis ditampilkan di bawah field jika validasi gagal.

  4. GlobalKey<FormState> digunakan untuk mengakses state dari widget Form, sehingga method validate() dapat dipanggil dari onPressed pada ElevatedButton. Method validate() mengembalikan true jika semua validator mengembalikan null, dan false jika ada validator yang mengembalikan pesan error.

  5. Controller perlu dibersihkan menggunakan method dispose() ketika widget sudah tidak digunakan agar tidak membebani memori.

  6. SnackBar yang dipanggil melalui ScaffoldMessenger.of(context).showSnackBar() dapat digunakan untuk menampilkan hasil inputan atau pesan berhasil kepada user.

  7. Penggunaan kata kunci const pada widget yang nilainya tetap dapat meningkatkan performa karena widget tersebut tidak di-build ulang. Namun widget yang menggunakan nilai yang berubah (seperti controller) tidak boleh menggunakan const.

  8. Pada tugas Kelas B, form pendaftaran pengguna berhasil dibuat dengan memisahkan kode menjadi dua file (main.dart dan user_registration_form.dart). Validasi berhasil diterapkan: semua inputan wajib diisi, email harus mengandung @, serta password dan confirm password harus sama. Jika semua valid, method _submitForm menampilkan pesan pendaftaran berhasil.