Skip to content

Instantly share code, notes, and snippets.

@sebald
Created March 23, 2022 11:27
Show Gist options
  • Save sebald/afd6d2f3c3252e65b2e632109e0cb2ed to your computer and use it in GitHub Desktop.
Save sebald/afd6d2f3c3252e65b2e632109e0cb2ed to your computer and use it in GitHub Desktop.
Trying to make the compound component pattern work for forms
import React, { useCallback, useContext, useRef, useState } from 'react';
import { useField as useAriaField } from '@react-aria/label';
import { useTextField } from '@react-aria/textfield';
const FieldContext = React.createContext<any>({});
const useFieldProvider = (props: any) => {
const [hasDescription, setHasDescription] = useState(false);
const field = useAriaField({ label: true, description: hasDescription });
const getLabelProps = useCallback(
(props = {}) => ({
...props,
...field.labelProps,
}),
[field.labelProps]
);
const getFieldProps = useCallback(
(props = {}) => ({
...props,
...field.fieldProps,
}),
[field.fieldProps]
);
const getDescriptionProps = useCallback(
(props = {}) => ({
...props,
...field.descriptionProps,
ref: (node: any) => {
if (!node) {
return;
}
setHasDescription(true);
},
}),
[field.descriptionProps]
);
return {
...field,
hasDescription,
getLabelProps,
getFieldProps,
getDescriptionProps,
};
};
const Field: React.FC<any> = ({ children, ...ownProps }) => {
const ctx = useFieldProvider(ownProps);
console.log(ctx); // check if react-aria generated the props for us! \o/
return <FieldContext.Provider value={ctx}>{children}</FieldContext.Provider>;
};
const Label: React.FC<any> = (props) => {
const ctx = useContext(FieldContext);
return <label {...ctx.getLabelProps(props)} />;
};
const Input = (props: any) => {
const ctx = useContext(FieldContext);
const ref = useRef(null);
const r = useTextField(ctx.getFieldProps(props), ref);
return <input {...r.inputProps} />;
};
const FieldDescription = React.forwardRef((props: any, ref: any) => {
const ctx = useContext(FieldContext);
return <div {...ctx.getDescriptionProps(props, ref)} />;
});
const App = () => (
<Field>
<Label>THE LABEL!</Label>
<Input />
<FieldDescription>Helpful text</FieldDescription>
</Field>
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment