diff --git a/packages/gamut-styles/src/variance/config.ts b/packages/gamut-styles/src/variance/config.ts
index 4ba51362f45..c76f30fba04 100644
--- a/packages/gamut-styles/src/variance/config.ts
+++ b/packages/gamut-styles/src/variance/config.ts
@@ -245,6 +245,21 @@ export const margin = {
mb: { property: 'marginBottom', scale: 'spacing' },
mr: { property: 'marginRight', scale: 'spacing' },
ml: { property: 'marginLeft', scale: 'spacing' },
+ // Logical properties
+ mbl: {
+ property: 'margin',
+ properties: ['marginBlockStart', 'marginBlockEnd'],
+ scale: 'spacing',
+ },
+ mbls: { property: 'marginBlockStart', scale: 'spacing' },
+ mble: { property: 'marginBlockEnd', scale: 'spacing' },
+ mi: {
+ property: 'margin',
+ properties: ['marginInlineStart', 'marginInlineEnd'],
+ scale: 'spacing',
+ },
+ mis: { property: 'marginInlineStart', scale: 'spacing' },
+ mie: { property: 'marginInlineEnd', scale: 'spacing' },
} as const;
export const padding = {
@@ -263,6 +278,21 @@ export const padding = {
pb: { property: 'paddingBottom', scale: 'spacing' },
pr: { property: 'paddingRight', scale: 'spacing' },
pl: { property: 'paddingLeft', scale: 'spacing' },
+ // Logical properties
+ pbl: {
+ property: 'padding',
+ properties: ['paddingBlockStart', 'paddingBlockEnd'],
+ scale: 'spacing',
+ },
+ pbls: { property: 'paddingBlockStart', scale: 'spacing' },
+ pble: { property: 'paddingBlockEnd', scale: 'spacing' },
+ pi: {
+ property: 'padding',
+ properties: ['paddingInlineStart', 'paddingInlineEnd'],
+ scale: 'spacing',
+ },
+ pis: { property: 'paddingInlineStart', scale: 'spacing' },
+ pie: { property: 'paddingInlineEnd', scale: 'spacing' },
} as const;
export const space = {
diff --git a/packages/styleguide/src/lib/Foundations/System/Props/Space.mdx b/packages/styleguide/src/lib/Foundations/System/Props/Space.mdx
index 0afcbb48e6a..cae665e79af 100644
--- a/packages/styleguide/src/lib/Foundations/System/Props/Space.mdx
+++ b/packages/styleguide/src/lib/Foundations/System/Props/Space.mdx
@@ -1,8 +1,9 @@
-import { Meta } from '@storybook/blocks';
+import { Canvas, Meta } from '@storybook/blocks';
import { AboutHeader, TokenTable } from '~styleguide/blocks';
import { defaultColumns, getPropRows } from '../../shared/elements';
+import * as SpaceStories from './Space.stories';
export const parameters = {
title: 'Space',
@@ -10,7 +11,7 @@ export const parameters = {
status: 'updating',
};
-
+
@@ -25,4 +26,20 @@ const SpaceExample = styled.div(system.space);
;
```
+## Logical Properties
+
+Logical spacing properties like `mbl` (marginBlock) provide RTL-aware spacing that adapts to text direction. The `mbl` prop applies margin to both block start and block end, which in LTR layouts is equivalent to margin-top and margin-bottom.
+
+### `mbl` (marginBlock)
+
+
+
+### `mi` (marginInline)
+
+The `mi` prop applies margin to both inline start and inline end, which in LTR layouts is equivalent to margin-left and margin-right.
+
+
+
+
+
diff --git a/packages/styleguide/src/lib/Foundations/System/Props/Space.stories.tsx b/packages/styleguide/src/lib/Foundations/System/Props/Space.stories.tsx
new file mode 100644
index 00000000000..7cf05b28909
--- /dev/null
+++ b/packages/styleguide/src/lib/Foundations/System/Props/Space.stories.tsx
@@ -0,0 +1,206 @@
+import {
+ Box,
+ FlexBox,
+ FormGroup,
+ Radio,
+ RadioGroup,
+ Text,
+} from '@codecademy/gamut';
+import type { Meta, StoryObj } from '@storybook/react';
+import { ChangeEvent, useState } from 'react';
+
+const meta: Meta = {
+ title: 'Foundations/System/Props/Space',
+ component: Box,
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const MarginBlock: Story = {
+ render: () => (
+
+
+ This box has mbl={32} (marginBlock), which applies margin
+ to both block start and block end. In LTR, this is equivalent to
+ margin-top and margin-bottom.
+
+
+
+ This box uses my={32} for comparison. Notice how the
+ logical property mbl provides the same visual result but is
+ RTL-aware.
+
+
+ ),
+};
+
+export const MarginInline: Story = {
+ render: () => (
+
+
+
+ This box has mi={32} (marginInline), which applies margin
+ to both inline start and inline end. In LTR, this is equivalent to
+ margin-left and margin-right.
+
+
+ This box uses mx={32} for comparison. Notice how the
+ logical property mi provides the same visual result but
+ is RTL-aware.
+
+
+
+ ),
+};
+
+export const RTLComparison: Story = {
+ render: () => {
+ const Component = () => {
+ const [direction, setDirection] = useState<'ltr' | 'rtl'>('ltr');
+ const [writingMode, setWritingMode] = useState<
+ 'horizontal-tb' | 'vertical-rl' | 'vertical-lr'
+ >('horizontal-tb');
+
+ return (
+
+ {/* Controls */}
+
+
+
+ ) => {
+ setDirection(event.target.value as 'ltr' | 'rtl');
+ }}
+ >
+
+
+
+
+
+
+
+ ) => {
+ setWritingMode(
+ event.target.value as
+ | 'horizontal-tb'
+ | 'vertical-rl'
+ | 'vertical-lr'
+ );
+ }}
+ >
+
+
+
+
+
+
+
+
+ {/* Demo Container */}
+
+
+ {direction === 'ltr' ? 'LTR' : 'RTL'} ({writingMode})
+
+
+
+
+
+
+ marginInlineStart={48}
+
+ Logical property
+
+
+ Margin on start (adapts to direction & writing mode)
+
+
+
+
+
+
+
+ marginLeft={48}
+
+ Physical property
+
+
+ Margin on left (always fixed)
+
+
+
+
+
+
+
+
+ Notice:
+ {' '}
+ marginInlineStart adapts to direction and writing mode,{' '}
+ marginLeft stays fixed
+
+
+ );
+ };
+ return ;
+ },
+};