diff --git a/packages/design-system/src/components/N8nButton/Button.vue b/packages/design-system/src/components/N8nButton/Button.vue
index 5e4f3bd580..b56c87ae85 100644
--- a/packages/design-system/src/components/N8nButton/Button.vue
+++ b/packages/design-system/src/components/N8nButton/Button.vue
@@ -25,7 +25,11 @@
:size="props.size"
/>
- {{ props.label }}
+
+
+ {{ props.label }}
+
+
diff --git a/packages/design-system/src/components/N8nCard/Card.stories.ts b/packages/design-system/src/components/N8nCard/Card.stories.ts
new file mode 100644
index 0000000000..c43f40b771
--- /dev/null
+++ b/packages/design-system/src/components/N8nCard/Card.stories.ts
@@ -0,0 +1,29 @@
+/* tslint:disable:variable-name */
+
+import N8nCard from './Card.vue';
+import {StoryFn} from "@storybook/vue";
+
+export default {
+ title: 'Atoms/Card',
+ component: N8nCard
+};
+
+export const Default: StoryFn = (args, {argTypes}) => ({
+ props: Object.keys(argTypes),
+ components: {
+ N8nCard,
+ },
+ template: `This is a card.`,
+});
+
+export const WithHeaderAndFooter: StoryFn = (args, {argTypes}) => ({
+ props: Object.keys(argTypes),
+ components: {
+ N8nCard,
+ },
+ template: `
+ Header
+ This is a card.
+ Footer
+ `,
+});
diff --git a/packages/design-system/src/components/N8nCard/Card.vue b/packages/design-system/src/components/N8nCard/Card.vue
new file mode 100644
index 0000000000..3d385f909f
--- /dev/null
+++ b/packages/design-system/src/components/N8nCard/Card.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
diff --git a/packages/design-system/src/components/N8nCard/__tests__/Card.spec.ts b/packages/design-system/src/components/N8nCard/__tests__/Card.spec.ts
new file mode 100644
index 0000000000..6d1a0f4cb8
--- /dev/null
+++ b/packages/design-system/src/components/N8nCard/__tests__/Card.spec.ts
@@ -0,0 +1,26 @@
+import {render} from '@testing-library/vue';
+import N8nCard from "../Card.vue";
+
+describe('components', () => {
+ describe('N8nCard', () => {
+ it('should render correctly', () => {
+ const wrapper = render(N8nCard, {
+ slots: {
+ default: 'This is a card.',
+ },
+ });
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+
+ it('should render correctly with header and footer', () => {
+ const wrapper = render(N8nCard, {
+ slots: {
+ header: 'Header',
+ default: 'This is a card.',
+ footer: 'Footer',
+ },
+ });
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+ });
+});
diff --git a/packages/design-system/src/components/N8nCard/index.ts b/packages/design-system/src/components/N8nCard/index.ts
new file mode 100644
index 0000000000..a2bc0e903c
--- /dev/null
+++ b/packages/design-system/src/components/N8nCard/index.ts
@@ -0,0 +1,3 @@
+import N8nCard from './Card.vue';
+
+export default N8nCard;
diff --git a/packages/design-system/src/components/index.js b/packages/design-system/src/components/index.js
index 01884e7cfc..068c4c21f1 100644
--- a/packages/design-system/src/components/index.js
+++ b/packages/design-system/src/components/index.js
@@ -38,6 +38,7 @@ import N8nActionToggle from './N8nActionToggle';
import N8nAvatar from './N8nAvatar';
import N8nBadge from './N8nBadge';
import N8nButton from './N8nButton';
+import N8nCard from './N8nCard';
import N8nFormBox from './N8nFormBox';
import N8nFormInput from './N8nFormInput';
import N8nFormInputs from './N8nFormInputs';
@@ -75,6 +76,7 @@ export {
N8nAvatar,
N8nBadge,
N8nButton,
+ N8nCard,
N8nHeading,
N8nFormBox,
N8nFormInput,
diff --git a/packages/design-system/theme/src/index.scss b/packages/design-system/theme/src/index.scss
index 2bc1d28de4..2b467348de 100644
--- a/packages/design-system/theme/src/index.scss
+++ b/packages/design-system/theme/src/index.scss
@@ -82,3 +82,4 @@
// @use "./avatar.scss";
@use "./drawer.scss";
// @use "./popconfirm.scss";
+@use "./utilities.scss";
diff --git a/packages/design-system/theme/src/utilities.scss b/packages/design-system/theme/src/utilities.scss
new file mode 100644
index 0000000000..024f983815
--- /dev/null
+++ b/packages/design-system/theme/src/utilities.scss
@@ -0,0 +1,19 @@
+@use 'sass:string';
+
+$spacing-sizes: '5xs', '4xs', '3xs', '2xs', 'xs', 's', 'm', 'l', 'xl', '2xl', '3xl', '4xl', '5xl';
+$spacing-properties: 'margin', 'padding';
+$spacing-sides: 'top', 'right', 'bottom', 'left';
+
+@each $size in $spacing-sizes {
+ @each $property in $spacing-properties {
+ @each $side in $spacing-sides {
+ .#{string.slice($property, 0, 1)}#{string.slice($side, 0, 1)}-#{$size} {
+ #{$property}-#{$side}: var(--spacing-#{$size}) !important;
+ }
+ }
+
+ .#{string.slice($property, 0, 1)}-#{$size} {
+ #{$property}: var(--spacing-#{$size}) !important;
+ }
+ }
+}