Skip to Content
UI playbookLogin & register

Login & register

Login / register — LoginForm

<Flex vertical justify="center" style={{ minHeight: "100vh", background: `linear-gradient(180deg, ${token.colorPrimaryBg} 0%, ${token.colorBgLayout} 45%)` }}> <LoginForm logo={<AuditOutlined style={{ fontSize: 40, color: token.colorPrimary }} />} title="Duyệt mua sắm" subTitle="Đề xuất, duyệt và theo dõi chi tiêu mua sắm" submitter={{ searchConfig: { submitText: "Đăng nhập" } }} message={error ? <Alert type="error" showIcon message={error} style={{ marginBottom: 24 }} /> : undefined} actions={<Typography.Text type="secondary">Chưa có tài khoản? <a onClick={() => nav("/register")}>Đăng ký</a></Typography.Text>} onFinish={async (v) => { try { const r = await api.auth.login(v); signIn(r.token, r.user); nav("/"); return true; } catch (e) { setError(errMsg(e)); return false; } }}> <ProFormText name="email" label="Email" fieldProps={{ size: "large", prefix: <MailOutlined /> }} rules={[{ required: true, type: "email" }]} /> <ProFormText.Password name="password" label="Mật khẩu" fieldProps={{ size: "large", prefix: <LockOutlined /> }} rules={[{ required: true }]} /> </LoginForm> </Flex>
  • Keep labels (accessibility + tests find fields by label). Server error goes in message, not a toast.

Đăng nhập — Đăng nhập: LoginForm của pro-components, có label (truy cập + test tìm theo label), lỗi server hiện trong `message`. Mở trong Playground →

Xem code (37 dòng)
// Đăng nhập: LoginForm của pro-components, có label (truy cập + test tìm theo label), lỗi server hiện trong `message`.
import { useState } from "react";
import { LoginForm, ProFormCheckbox, ProFormText } from "@ant-design/pro-components";
import { Alert, Flex, Typography, theme } from "antd";
import { AuditOutlined, LockOutlined, MailOutlined } from "@ant-design/icons";

export default function Page() {
  const { token } = theme.useToken();
  const [error, setError] = useState<string | null>(null);
  return (
    <Flex vertical justify="center" style={{ minHeight: "100vh", background: `linear-gradient(180deg, ${token.colorPrimaryBg} 0%, ${token.colorBgLayout} 45%)` }}>
      <LoginForm
        logo={<AuditOutlined style={{ fontSize: 40, color: token.colorPrimary }} />}
        title="Duyệt mua sắm"
        subTitle="Đề xuất, duyệt và theo dõi chi tiêu mua sắm"
        submitter={{ searchConfig: { submitText: "Đăng nhập" } }}
        initialValues={{ remember: true }}
        message={error ? <Alert type="error" showIcon title={error} style={{ marginBottom: 24 }} /> : undefined}
        actions={<Typography.Text type="secondary">Chưa có tài khoản? <a>Đăng ký</a></Typography.Text>}
        onFinish={async (v: { email: string; password: string }) => {
          // Thử: mật khẩu khác "123456" sẽ báo lỗi như server trả 401.
          if (v.password !== "123456") { setError("Sai email hoặc mật khẩu"); return false; }
          setError(null);
          return true;
        }}
      >
        <ProFormText name="email" label="Email" placeholder="ten@congty.vn" fieldProps={{ size: "large", prefix: <MailOutlined /> }} rules={[{ required: true, type: "email", message: "Nhập email hợp lệ" }]} />
        <ProFormText.Password name="password" label="Mật khẩu" placeholder="Mật khẩu" fieldProps={{ size: "large", prefix: <LockOutlined /> }} rules={[{ required: true, message: "Nhập mật khẩu" }]} />
        <div style={{ marginBlockEnd: 24 }}>
          <ProFormCheckbox noStyle name="remember">Ghi nhớ đăng nhập</ProFormCheckbox>
          <a style={{ float: "right" }}>Quên mật khẩu?</a>
        </div>
      </LoginForm>
    </Flex>
  );
}
Last updated on