diff --git a/packages/form/widgets/segmented/demo/simple.md b/packages/form/widgets/segmented/demo/simple.md
new file mode 100644
index 0000000000..9afa849841
--- /dev/null
+++ b/packages/form/widgets/segmented/demo/simple.md
@@ -0,0 +1,65 @@
+---
+title:
+ zh-CN: 基础样例
+ en-US: Basic Usage
+order: 0
+---
+
+## zh-CN
+
+最简单的用法。
+
+## en-US
+
+Simplest of usage.
+
+```ts
+import { Component } from '@angular/core';
+import { delay, of } from 'rxjs';
+
+import { SFSchema } from '@delon/form';
+import { SFSegmentedWidgetSchema, SegmentedWidget } from '@delon/form/widgets/segmented';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NzSegmentedOptions } from 'ng-zorro-antd/segmented';
+
+@Component({
+ selector: 'app-demo',
+ template: ``
+})
+export class DemoComponent {
+ schema: SFSchema = {
+ properties: {
+ base: {
+ type: 'string',
+ title: 'Base',
+ default: 2,
+ enum: ['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly'],
+ ui: {
+ widget: SegmentedWidget.KEY,
+ valueChange: console.log
+ } as SFSegmentedWidgetSchema
+ },
+ asyncData: {
+ type: 'string',
+ title: 'Async Data',
+ ui: {
+ widget: SegmentedWidget.KEY,
+ asyncData: () =>
+ of([
+ { label: 'Label1', value: 'a' },
+ { label: 'Label2', value: 'b' },
+ { label: 'Label3', value: 'c', disabled: true }
+ ] as NzSegmentedOptions).pipe(delay(1000)),
+ valueChange: console.log
+ } as SFSegmentedWidgetSchema
+ }
+ }
+ };
+
+ constructor(private msg: NzMessageService) {}
+
+ submit(value: {}): void {
+ this.msg.success(JSON.stringify(value));
+ }
+}
+```
diff --git a/packages/form/widgets/segmented/index.en-US.md b/packages/form/widgets/segmented/index.en-US.md
new file mode 100644
index 0000000000..a688d37a56
--- /dev/null
+++ b/packages/form/widgets/segmented/index.en-US.md
@@ -0,0 +1,22 @@
+---
+title: segmented
+subtitle: Segmented
+type: Non-built-in widgets
+---
+
+- When displaying multiple options and user can select a single option;
+- When switching the selected option, the content of the associated area changes.
+
+## Import module
+
+Non-built-in modules, Should be import `SegmentedWidgetModule` in [json-schema.module.ts](https://github.com/ng-alain/ng-alain/blob/master/src/app/shared/json-schema/json-schema.module.ts#L11).
+
+## API
+
+### ui
+
+| Property | Description | Type | Default |
+|----------|-------------|------|---------|
+| `[block]` | Option to fit width to its parent\'s width | `boolean` | false | |
+| `[asyncData]` | Set children optional | `() => Observable` | - | |
+| `(valueChange)` | Emits when index of the currently selected option changes | `(data: { index: number; item: SFValue }) => void` | - | |
diff --git a/packages/form/widgets/segmented/index.ts b/packages/form/widgets/segmented/index.ts
new file mode 100644
index 0000000000..97019ccd83
--- /dev/null
+++ b/packages/form/widgets/segmented/index.ts
@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+
+import { DelonFormModule, WidgetRegistry } from '@delon/form';
+import { NzSegmentedModule } from 'ng-zorro-antd/segmented';
+
+import { SegmentedWidget } from './widget';
+
+export * from './widget';
+export * from './schema';
+
+@NgModule({
+ imports: [FormsModule, DelonFormModule, NzSegmentedModule],
+ declarations: [SegmentedWidget]
+})
+export class SegmentedWidgetModule {
+ constructor(widgetRegistry: WidgetRegistry) {
+ widgetRegistry.register(SegmentedWidget.KEY, SegmentedWidget);
+ }
+}
diff --git a/packages/form/widgets/segmented/index.zh-CN.md b/packages/form/widgets/segmented/index.zh-CN.md
new file mode 100644
index 0000000000..a7c765d643
--- /dev/null
+++ b/packages/form/widgets/segmented/index.zh-CN.md
@@ -0,0 +1,22 @@
+---
+title: segmented
+subtitle: 分段控制器
+type: Non-built-in widgets
+---
+
+- 用于展示多个选项并允许用户选择其中单个选项;
+- 当切换选中选项时,关联区域的内容会发生变化。
+
+## 导入模块
+
+非内置模块,需要额外在 [json-schema.module.ts](https://github.com/ng-alain/ng-alain/blob/master/src/app/shared/json-schema/json-schema.module.ts#L11) 导入 `SegmentedWidgetModule`。
+
+## API
+
+### ui 属性
+
+| 成员 | 说明 | 类型 | 默认值 |
+|----|----|----|-----|
+| `[block]` | 将宽度调整为父元素宽度的选项 | `boolean` | false | |
+| `[asyncData]` | 异步数据 | `() => Observable` | - | |
+| `(valueChange)` | 当前选中项目变化时触发回调 | `(data: { index: number; item: SFValue }) => void` | - | |
diff --git a/packages/form/widgets/segmented/ng-package.json b/packages/form/widgets/segmented/ng-package.json
new file mode 100644
index 0000000000..ec57a9fa30
--- /dev/null
+++ b/packages/form/widgets/segmented/ng-package.json
@@ -0,0 +1,6 @@
+{
+ "lib": {
+ "flatModuleFile": "widgets-color",
+ "entryFile": "index.ts"
+ }
+}
diff --git a/packages/form/widgets/segmented/schema.ts b/packages/form/widgets/segmented/schema.ts
new file mode 100644
index 0000000000..897c7539b6
--- /dev/null
+++ b/packages/form/widgets/segmented/schema.ts
@@ -0,0 +1,21 @@
+import type { TemplateRef } from '@angular/core';
+import type { Observable } from 'rxjs';
+
+import type { SFUISchemaItem, SFValue } from '@delon/form';
+import type { NzSegmentedOption, NzSegmentedOptions } from 'ng-zorro-antd/segmented';
+
+export interface SFSegmentedWidgetSchema extends SFUISchemaItem {
+ /**
+ * 异步数据源
+ */
+ asyncData?: () => Observable;
+ /**
+ * Option to fit width to its parent's width
+ */
+ block?: boolean;
+ labelTemplate?: TemplateRef<{ $implicit: NzSegmentedOption; index: number }> | null;
+ /**
+ * Emits when index of the currently selected option changes
+ */
+ valueChange?: (data: { index: number; item: SFValue }) => void;
+}
diff --git a/packages/form/widgets/segmented/widget.spec.ts b/packages/form/widgets/segmented/widget.spec.ts
new file mode 100644
index 0000000000..2a503c199c
--- /dev/null
+++ b/packages/form/widgets/segmented/widget.spec.ts
@@ -0,0 +1,42 @@
+import { DebugElement } from '@angular/core';
+import { ComponentFixture, fakeAsync } from '@angular/core/testing';
+
+import { SFSchema } from '@delon/form';
+import { createTestContext } from '@delon/testing';
+
+import { SegmentedWidgetModule, SFSegmentedWidgetSchema } from './index';
+import { configureSFTestSuite, SFPage, TestFormComponent } from '../../spec/base.spec';
+
+describe('form: widget: segmented', () => {
+ let fixture: ComponentFixture;
+ let dl: DebugElement;
+ let context: TestFormComponent;
+ let page: SFPage;
+
+ configureSFTestSuite({ imports: [SegmentedWidgetModule] });
+
+ beforeEach(() => {
+ ({ fixture, dl, context } = createTestContext(TestFormComponent));
+ page = new SFPage(context.comp);
+ page.cleanOverlay().prop(dl, context, fixture);
+ });
+
+ it('should be working', fakeAsync(() => {
+ const valueChange = jasmine.createSpy();
+ const s: SFSchema = {
+ properties: {
+ a: {
+ type: 'string',
+ enum: ['Daily', 'Weekly', 'Monthly', 'Quarterly', 'Yearly'],
+ ui: {
+ widget: 'segmented',
+ valueChange
+ } as SFSegmentedWidgetSchema
+ }
+ }
+ };
+ page.newSchema(s).typeEvent('click', '.ant-segmented-item:nth-child(2) .ant-segmented-item-label');
+ expect(page.getValue('/a')).toBe(1);
+ expect(valueChange).toHaveBeenCalled();
+ }));
+});
diff --git a/packages/form/widgets/segmented/widget.ts b/packages/form/widgets/segmented/widget.ts
new file mode 100644
index 0000000000..d97ab147bb
--- /dev/null
+++ b/packages/form/widgets/segmented/widget.ts
@@ -0,0 +1,51 @@
+import { Component, ViewEncapsulation } from '@angular/core';
+
+import { ControlUIWidget, SFValue, getData } from '@delon/form';
+import { NzSegmentedOptions } from 'ng-zorro-antd/segmented';
+
+import type { SFSegmentedWidgetSchema } from './schema';
+
+@Component({
+ selector: 'sf-segmented',
+ template: `
+
+ `,
+ preserveWhitespaces: false,
+ encapsulation: ViewEncapsulation.None
+})
+export class SegmentedWidget extends ControlUIWidget {
+ static readonly KEY = 'segmented';
+ private _list?: NzSegmentedOptions;
+ get list(): NzSegmentedOptions {
+ return this._list ?? [];
+ }
+
+ reset(value: SFValue): void {
+ getData(this.schema, this.ui, value).subscribe(list => {
+ this._list = list as NzSegmentedOptions;
+ this.detectChanges();
+ });
+ }
+
+ valueChange(index: number): void {
+ if (this.ui.valueChange) {
+ this.ui.valueChange({ index, item: this.list[index] as SFValue });
+ }
+ }
+}
diff --git a/src/app/shared/json-schema/json-schema.module.ts b/src/app/shared/json-schema/json-schema.module.ts
index 61bb9e095b..43932b3b5f 100644
--- a/src/app/shared/json-schema/json-schema.module.ts
+++ b/src/app/shared/json-schema/json-schema.module.ts
@@ -7,6 +7,7 @@ import { ColorWidgetModule } from '@delon/form/widgets/color';
import { MentionWidgetModule } from '@delon/form/widgets/mention';
import { QrCodeWidgetModule } from '@delon/form/widgets/qr-code';
import { RateWidgetModule } from '@delon/form/widgets/rate';
+import { SegmentedWidgetModule } from '@delon/form/widgets/segmented';
import { SliderWidgetModule } from '@delon/form/widgets/slider';
import { TagWidgetModule } from '@delon/form/widgets/tag';
import { TimeWidgetModule } from '@delon/form/widgets/time';
@@ -34,6 +35,7 @@ import { SharedModule } from '../shared.module';
UploadWidgetModule,
ColorWidgetModule,
QrCodeWidgetModule,
+ SegmentedWidgetModule,
MonacoEditorWidgetModule,
TinymceWidgetModule
]