Advanced: Using Components as Props
Advanced Usage
The below showcases three different approaches to using Components as Props. Currently, this feature is only available for our React renderer.
- Typescript configuration (with infer spec enabled)
- Manual configuration within the Knapsack UI
- Manual configuration by editing code (the pattern data file associated with
Method #1: Typescript Configuration (with infer spec enabled)
- Verify your component is using infer spec (see this guide if you need help)
- When defining your prop for passing components be sure to use either
React.FC
orReact.VFC
(as shown in the examples below) - In the component that is taking Components as Props — be sure to convert the prop to the component format with
callToAction: CallToActionSlot
(React components must be capitalized) - Finally, add the component to the return (
<CallToActionSlot>Text Here </CallToActionSlot>
) - All that is left now is, within the Knapsack UI, select the component to pass in as a prop!
Consider this example Chip component:
import * as React from 'react'; import clsx from 'clsx'; export interface ChipProps { children: React.ReactNode | string; color?: 'neutral' | 'info'; size?: 'small' | 'medium'; className?: string; } export const Chip: React.FC<ChipProps> = ({ children, color = 'info', size = 'medium', className, }: ChipProps) => { const classes = clsx( className, 'ex-chip', `ex-chip--${color}`, `ex-chip--${size}`, ); return <div className={classes}>{children}</div>; };
Now consider this Card component that is able to use a Component as a Prop ( callToAction
):
import * as React from 'react'; type ImageSrc = string; type Title = string; type Subtitle = string; export interface CardProps { img?: ImageSrc; title?: Title; subtitle?: Subtitle; children?: React.ReactNode; /** * Text used with the optional callToAction slot */ ctaText?: string; /** * Optional Call To Action. Ideal for Chips and Buttons */ callToAction?: React.FC; } export const Card: React.FC<CardProps> = ({ title, subtitle, children, img, ctaText, callToAction: CallToActionSlot, }) => { return ( <div className="ex-card"> {img && <img src={img} className="ex-card_img" alt="" />} <div className="ex-card_body"> {title && <h4 className="ex-card_title">{title}</h4>} {subtitle && <h6 className="ex-card_subtitle">{subtitle}</h6>} {children && <div>{children}</div>} {CallToActionSlot && ( <div style={{ marginTop: '1rem', }} > <CallToActionSlot> {ctaText ?? 'Default CTA text'} </CallToActionSlot> </div> )} </div> </div> ); };
Given the above examples — we are able to use our callToAction
prop to pass in our Chip component. We could do the same for a Button, Link, or any other component that best fits our need.
Method #2: Manual Configuration (in the UI)
Note: For this example we will use the same architecture as the above Typescript example with callToActionManual: CallToActionSlot
(React components must be capitalized).
- Within your browser in the Knapsack UI — navigate to the pattern you'd like to add the Component as a Prop.
- Edit the component spec by clicking the gear icon:
- Scroll down to the "Slots" spec and add a new slot:
- For our example, we'll add a new slot called
callToActionManual
. Toggle open the configuration of the new slot and enable "Component as a prop" (you'll note enabling this option also sets the "One item per slot" and "Disallow text" options, which are required for this to work correctly: - Click the purple "Save Changes" button and then close the overlay by clicking away from it.
- In the UI, select a component to pass as the prop and enjoy! 🎉
Method #3: Manual Configuration (in the code)
- Locate and edit the data file associated with your pattern (for example,
knapsack.pattern.card.json
) - In the
"spec"
, within the specific"slots"
item you’d like to use as a prop — add the following three flags:
"allowOnlyOne": true, "disallowText": true, "isTemplateReference": true
For a slot called "component", it should look like the below:
"spec": { "slots": { "component": { "title": "component", "allowOnlyOne": true, "disallowText": true, "isTemplateReference": true } } }
- Next, navigate back to your component within the Knapsack UI and add your component to be used as a prop!
- Have fun using Components as Props! 🎉