diff --git a/next-ui/src/App.vue b/next-ui/src/App.vue
index f39946ec..345ddcf1 100644
--- a/next-ui/src/App.vue
+++ b/next-ui/src/App.vue
@@ -3,8 +3,8 @@
-
-
+
+
diff --git a/next-ui/src/components.d.ts b/next-ui/src/components.d.ts
index 0ac26853..fbae7f4b 100644
--- a/next-ui/src/components.d.ts
+++ b/next-ui/src/components.d.ts
@@ -19,6 +19,7 @@ declare module 'vue' {
FragmentLocaleSelector: typeof import('./fragments/fragment/LocaleSelector.vue')['default']
FragmentSnackQueue: typeof import('./fragments/fragment/SnackQueue.vue')['default']
FragmentThemeSelector: typeof import('./fragments/fragment/ThemeSelector.vue')['default']
+ FragmentUserFormCreateEdit: typeof import('./fragments/fragment/user/form/CreateEdit.vue')['default']
HelloWorld: typeof import('./components/HelloWorld.vue')['default']
LayoutAppBar: typeof import('./fragments/layout/app/Bar.vue')['default']
LayoutAppDrawer: typeof import('./fragments/layout/app/drawer/Drawer.vue')['default']
diff --git a/next-ui/src/components/user/form/ChangePassword.stories.ts b/next-ui/src/components/user/form/ChangePassword.stories.ts
new file mode 100644
index 00000000..4be89916
--- /dev/null
+++ b/next-ui/src/components/user/form/ChangePassword.stories.ts
@@ -0,0 +1,60 @@
+import type { Meta, StoryObj } from '@storybook/vue3-vite'
+
+import ChangePassword from './ChangePassword.vue'
+import { expect, waitFor } from 'storybook/test'
+
+const meta = {
+ component: ChangePassword,
+ render: (args: object) => ({
+ components: { ChangePassword },
+ setup() {
+ return { args }
+ },
+ template: '',
+ }),
+ parameters: {
+ // More on how to position stories at: https://storybook.js.org/docs/configure/story-layout
+ },
+ args: {},
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Default: Story = {
+ args: {},
+}
+
+export const MatchingPasswords: Story = {
+ args: {},
+ play: async ({ canvas, userEvent }) => {
+ const password1 = canvas.getByLabelText(/new password/i, {
+ selector: 'input',
+ })
+ await userEvent.type(password1, 'abc')
+
+ const password2 = canvas.getByLabelText(/confirm password/i, {
+ selector: 'input',
+ })
+ await userEvent.type(password2, 'abc')
+
+ await waitFor(() => expect(canvas.getByText(/must be identical/i)).not.toBeVisible())
+ },
+}
+
+export const DifferentPasswords: Story = {
+ args: {},
+ play: async ({ canvas, userEvent }) => {
+ const password1 = canvas.getByLabelText(/new password/i, {
+ selector: 'input',
+ })
+ await userEvent.type(password1, 'abc')
+
+ const password2 = canvas.getByLabelText(/confirm password/i, {
+ selector: 'input',
+ })
+ await userEvent.type(password2, 'def')
+
+ await waitFor(() => expect(canvas.getByText(/must be identical/i)).toBeVisible())
+ },
+}
diff --git a/next-ui/src/components/user/form/ChangePassword.vue b/next-ui/src/components/user/form/ChangePassword.vue
index da6e85f7..e07f94e9 100644
--- a/next-ui/src/components/user/form/ChangePassword.vue
+++ b/next-ui/src/components/user/form/ChangePassword.vue
@@ -44,7 +44,7 @@