` element.
+
+
+
+## Examples
+
+### With Label and Description
+
+Here's a simple input with a label and description.
+
+
}
+ code={`
+ Name
+ Visible on your profile
+
+ `}
+/>
diff --git a/canon-docs/src/app/(docs)/components/input/page.mdx b/canon-docs/src/app/(docs)/components/input/page.mdx
index 49cb7bd08c..802003501e 100644
--- a/canon-docs/src/app/(docs)/components/input/page.mdx
+++ b/canon-docs/src/app/(docs)/components/input/page.mdx
@@ -2,11 +2,7 @@ import { PropsTable } from '@/components/PropsTable';
import { Snippet } from '@/components/Snippet';
import { Tabs } from '@/components/Tabs';
import { CodeBlock } from '@/components/CodeBlock';
-import {
- InputPreview,
- InputLabelAndDescription,
- InputError,
-} from '@/snippets/input';
+import { InputPreview, InputSizes } from '@/snippets/input';
import { BaseUI } from '@/components/HeadlessBanners/BaseUI';
# Input
@@ -37,57 +33,21 @@ A input component tfor your forms.
We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with
your brand. For additional flexibility, you can use the provided class names for each element listed below.
`}
+ code={`
`}
/>
## API reference
-
+
}
- code={`
`}
-/>
-
-### Error
-
-Here's a simple input with an error message.
-
-
}
- code={`
`}
+ preview={
}
+ code={`
+
+
+ `}
/>
diff --git a/canon-docs/src/app/(playground)/playground/page.tsx b/canon-docs/src/app/(playground)/playground/page.tsx
index 9478160517..0a03530629 100644
--- a/canon-docs/src/app/(playground)/playground/page.tsx
+++ b/canon-docs/src/app/(playground)/playground/page.tsx
@@ -67,9 +67,9 @@ const Content = () => {
{selectedComponents.find(c => c === 'text') && (
} title="Text" />
)}
- {selectedComponents.find(c => c === 'input') && (
+ {/* {selectedComponents.find(c => c === 'input') && (
} title="Input" />
- )}
+ )} */}
);
};
diff --git a/canon-docs/src/components/PropsTable/PropsTable.tsx b/canon-docs/src/components/PropsTable/PropsTable.tsx
index 6eb1f8cd88..555df84903 100644
--- a/canon-docs/src/components/PropsTable/PropsTable.tsx
+++ b/canon-docs/src/components/PropsTable/PropsTable.tsx
@@ -30,11 +30,15 @@ export const PropsTable =
>({
{n}
- {Array.isArray(data[n].type) ? (
- data[n].type.map(t => {t})
- ) : (
- {data[n].type}
- )}
+
+ {Array.isArray(data[n].type) ? (
+ data[n].type.map(t => {t})
+ ) : (
+ {data[n].type}
+ )}
+
{data[n].responsive ? 'Yes' : 'No'}
diff --git a/canon-docs/src/mdx-components.tsx b/canon-docs/src/mdx-components.tsx
index 308356bc67..59eee5e18f 100644
--- a/canon-docs/src/mdx-components.tsx
+++ b/canon-docs/src/mdx-components.tsx
@@ -15,7 +15,8 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
fontFamily: 'var(--docs-font)',
fontSize: '3rem',
fontWeight: 'var(--canon-font-weight-bold)',
- margin: 0,
+ marginTop: '4rem',
+ marginBottom: '0.5rem',
}}
>
{children as ReactNode}
@@ -36,30 +37,30 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
),
h3: ({ children }) => (
-
-
- {children as ReactNode}
-
-
+
+ {children as ReactNode}
+
),
p: ({ children }) => (
-
-
- {children as ReactNode}
-
-
+
+ {children as ReactNode}
+
),
a: ({ children, href }) => (
diff --git a/canon-docs/src/snippets/field.tsx b/canon-docs/src/snippets/field.tsx
new file mode 100644
index 0000000000..fe38c439ec
--- /dev/null
+++ b/canon-docs/src/snippets/field.tsx
@@ -0,0 +1,21 @@
+import { Input, Field, Grid } from '../../../packages/canon';
+
+export const FieldPreview = () => {
+ return (
+
+
+ Name
+
+ Visible on your profile
+
+
+ );
+};
+
+export const InputPlayground = () => {
+ return (
+
+
+
+ );
+};
diff --git a/canon-docs/src/snippets/input.tsx b/canon-docs/src/snippets/input.tsx
index 85db7cde19..b4479435d4 100644
--- a/canon-docs/src/snippets/input.tsx
+++ b/canon-docs/src/snippets/input.tsx
@@ -1,30 +1,26 @@
-import { Input } from '@backstage/canon';
+import { Input, Inline, Grid } from '../../../packages/canon';
export const InputPreview = () => {
return (
-
+
);
};
-export const InputLabelAndDescription = () => {
+export const InputSizes = () => {
return (
-
-
-
+
+
+
+
);
};
export const InputError = () => {
return (
-
+
);
};
@@ -32,7 +28,7 @@ export const InputError = () => {
export const InputPlayground = () => {
return (
-
+
);
};
diff --git a/canon-docs/src/utils/data.ts b/canon-docs/src/utils/data.ts
index 41ae4c0536..1109d6fa0a 100644
--- a/canon-docs/src/utils/data.ts
+++ b/canon-docs/src/utils/data.ts
@@ -77,6 +77,11 @@ export const components: Page[] = [
slug: 'checkbox',
status: 'alpha',
},
+ {
+ title: 'Field',
+ slug: 'field',
+ status: 'alpha',
+ },
{
title: 'Heading',
slug: 'heading',
diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md
index 058250c599..8f5e693271 100644
--- a/packages/canon/report.api.md
+++ b/packages/canon/report.api.md
@@ -6,6 +6,7 @@
///
import type { CSSProperties } from 'react';
+import { Field as Field_2 } from '@base-ui-components/react/field';
import { ForwardRefExoticComponent } from 'react';
import { Input as Input_2 } from '@base-ui-components/react/input';
import { default as React_2 } from 'react';
@@ -181,6 +182,37 @@ export interface ContainerProps {
// @public (undocumented)
export type Display = 'none' | 'flex' | 'block' | 'inline';
+// Warning: (ae-missing-release-tag) "Field" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal)
+//
+// @public (undocumented)
+export const Field: {
+ Root: React_2.ForwardRefExoticComponent<
+ Omit, 'ref'> &
+ React_2.RefAttributes
+ >;
+ Label: React_2.ForwardRefExoticComponent<
+ Omit, 'ref'> &
+ React_2.RefAttributes
+ >;
+ Description: React_2.ForwardRefExoticComponent<
+ Omit<
+ Field_2.Description.Props & React_2.RefAttributes,
+ 'ref'
+ > &
+ React_2.RefAttributes
+ >;
+ Error: React_2.ForwardRefExoticComponent<
+ Omit, 'ref'> &
+ React_2.RefAttributes
+ >;
+ Validity: ({
+ children,
+ ...props
+ }: React_2.ComponentPropsWithoutRef<
+ typeof Field_2.Validity
+ >) => React_2.JSX.Element;
+};
+
// @public (undocumented)
export type FlexDirection = 'row' | 'column';
diff --git a/packages/canon/src/components/Field/Field.stories.tsx b/packages/canon/src/components/Field/Field.stories.tsx
index 911bb07245..b949010f5f 100644
--- a/packages/canon/src/components/Field/Field.stories.tsx
+++ b/packages/canon/src/components/Field/Field.stories.tsx
@@ -64,3 +64,24 @@ export const WithError: Story = {
),
};
+
+export const WithValidity: Story = {
+ render: () => (
+
+ value !== 'Backstage' ? 'Please enter a different name' : null
+ }
+ >
+ Name
+
+
+ An error will show if the value is not Backstage
+
+
+ {validityState => (
+ {validityState.value ? 'Not Backstage' : 'Backstage'}
+ )}
+
+
+ ),
+};
diff --git a/packages/canon/src/components/Field/Field.styles.css b/packages/canon/src/components/Field/Field.styles.css
index 485cf32c15..bcafd0eeee 100644
--- a/packages/canon/src/components/Field/Field.styles.css
+++ b/packages/canon/src/components/Field/Field.styles.css
@@ -43,3 +43,11 @@
margin: 0;
padding-top: var(--canon-spacing-3xs);
}
+
+.canon-FieldValidity {
+ font-size: var(--canon-font-size-caption);
+ font-weight: var(--canon-font-weight-regular);
+ color: var(--canon-text-secondary);
+ margin: 0;
+ padding-top: var(--canon-spacing-3xs);
+}
diff --git a/packages/canon/src/components/Field/Field.tsx b/packages/canon/src/components/Field/Field.tsx
index 2e512e7944..013a3ef5b5 100644
--- a/packages/canon/src/components/Field/Field.tsx
+++ b/packages/canon/src/components/Field/Field.tsx
@@ -68,10 +68,17 @@ FieldError.displayName = FieldPrimitive.Error.displayName;
const FieldValidity = ({
children,
+ className,
...props
-}: React.ComponentPropsWithoutRef) => (
+}: React.ComponentPropsWithoutRef & {
+ className?: string;
+}) => (
- {validityState => children(validityState)}
+ {validityState => (
+
+ {children(validityState)}
+
+ )}
);
diff --git a/packages/canon/src/components/Input/Input.styles.css b/packages/canon/src/components/Input/Input.styles.css
index f1ac7a5580..4fe336fe30 100644
--- a/packages/canon/src/components/Input/Input.styles.css
+++ b/packages/canon/src/components/Input/Input.styles.css
@@ -23,6 +23,7 @@
font-weight: var(--canon-font-weight-regular);
color: var(--canon-text-primary);
transition: border-color 0.2s ease-in-out, outline-color 0.2s ease-in-out;
+ width: 100%;
}
.canon-Input::placeholder {
diff --git a/packages/canon/src/components/Input/Input.tsx b/packages/canon/src/components/Input/Input.tsx
index 5eb68e7bf4..c07f13fabe 100644
--- a/packages/canon/src/components/Input/Input.tsx
+++ b/packages/canon/src/components/Input/Input.tsx
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+'use client';
+
import React, { ElementRef, forwardRef } from 'react';
import { Input as InputPrimitive } from '@base-ui-components/react/input';
import clsx from 'clsx';
diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts
index 04f29c4b77..987aa959de 100644
--- a/packages/canon/src/index.ts
+++ b/packages/canon/src/index.ts
@@ -38,6 +38,6 @@ export * from './components/Icon';
export * from './components/Checkbox';
export * from './components/Table';
export * from './components/Input';
-
+export * from './components/Field';
// Types
export * from './types';