Custom prop controls for code components

You can create components with custom prop controls.

First, note that you may not need custom controls! If all you want is to show a dynamic set of options in a dropdown, or conditionally show/hide fields, you can use prop control functions.

When registering your component, specify type: ”custom” and a React copmonent that renders the control.

A minimal example:

Copy
// A code component that just renders the prop
const CodeComponent = ({ customProp, className }) => <div className={className}>{`${customProp}`}</div>;
// A prop control with the value and a button to update it
const CustomProp = ({ updateValue, value }) => (
<div
style={{
width: '100%',
display: 'flex',
justifyContent: 'space-between',
padding: '0px 10px 0px 10px'
}}
>
<span>Value: {`${value}`}.</span>
<button onClick={() => updateValue(!value)} style={{ background: 'lightgray', padding: '0px 5px 0px 5px' }}>
Change
</button>
</div>
);
// Registration
PLASMIC.registerComponent(CodeComponent, {
name: 'CodeComponent',
props: {
customProp: {
type: 'custom',
control: CustomProp
}
}
});

The props passed to the custom control component are:

  • componentProps: The props that were passed to the component
  • contextData: The data from setControlContextData(). See prop control functions.
  • value: The current value passed to the prop.
  • updateValue: The callback function to update the value to be passed to the prop.
  • FullscreenModal and SideModal: Modal components if the control needs more space (covering either the center of the entire screen, or just the right pane—see next section).

A shorthand if the prop registration doesn’t need to specify any other metadata is to provide the component directly:

Copy
PLASMIC.registerComponent(CodeComponent, {
name: 'CodeComponent',
props: {
customProp: CustomProp
}
});

Showing modals

To show a modal, use FullscreenModal or SideModal. These take an onClose callback, which is fired if users click outside.

Copy
const CustomControl = ({ FullscreenModal }) => {
const [open, setOpen] = useState(false);
return (
<div
style={{
width: '100%',
display: 'flex',
justifyContent: 'space-between',
padding: '0px 10px 0px 10px'
}}
>
<button onClick={() => setOpen(true)} style={{ background: 'lightgray', padding: '0px 5px 0px 5px' }}>
Edit
</button>
<FullscreenModal show={open} onClose={() => setOpen(false)}>
<div>More UI here!</div>
<button onClick={() => setOpen(false)}>Close</button>
</FullscreenModal>
</div>
);
};

Usage notes

The controls run inside the Plasmic Studio UI, which is running in a different document/iframe than your application/your app host.

This has a few current implications:

Context from your app host won’t be there. If your components need context (e.g. for styling), for now you will need to wrap each component, like so:

Copy
function StandardContexts({ children }) {
return (
<ThemeProvider>
<SomeOtherProvider>{children}</SomeOtherProvider>
</ThemeProvider>
);
}
function CustomProp1(props) {
return <StandardContexts>...</StandardContexts>;
}
function CustomProp2(props) {
return <StandardContexts>...</StandardContexts>;
}

And, styling must be provided explicitly. Things will be fine if you are using a CSS-in-JS solution that dynamically injects styles into the document, but if you need external stylesheets to be loaded, then you will need to include and manage those yourself.

Was this page helpful?

Have feedback on this page? Let us know on our forum.