export const meta = { title: `Extend via code`, description: `Figma to React code with Amplify Studio`, }; When you run `amplify pull`, Amplify automatically generates JSX and TS versions of your Figma components. You cannot directly edit the code for these components as they will get overwritten on the next `pull`, but you have exposed mechanisms to extend the code. ## Extend generated code ### Extend generated code via component prop When using Figma created components, you can use any exposed component props. The example code below shows how you can add pagination to a collection. The `isPaginated` prop is a property of the [``](https://ui.docs.amplify.aws/react/components/collection) component. Similarly, you can use any prop such as `gap` or `isSearchable` to extend the collection. ``` import {AmpligramCollection} from './ui-components' ``` ### Extend generated components via overrides prop All generated code exposes an `overrides` prop on all components and children to give you full control over extending generated code. The following example shows how to override the color of the title of the `FAQItem` component, that is part of the default Figma file, to red. 1. In Studio, navigate to the `FAQItem` component 2. Find the name of the text element, in this case `Title` 3. Wherever you are rendering the `FAQItem` add an `overrides` prop.
![override](/images/console/ui-override.png) ```jsx import {FAQItem} from './ui-components' ... ... //⬇️ Element name shown in Studio ```
### Extend generated collections via overrideItems prop All generated Collection code exposes an `overrideItems` prop to give you full control to extend each collection item with context its data item. `overrideItems` expects a function that accepts an `{ item, index }` parameter and returns the override props that should be applied to each collection item. The following example shows how to override each collection item to show a different color based on their index in the collection and alerts the user of which the clicked home. ```jsx ({ backgroundColor: index % 2 === 0 ? 'white' : 'lightgray', onClick: () => alert(`Home with id: ${item.id} and ${item.address} clicked!`) })} /> ``` ![Collection item shows a different color based on their index in the collection and alerts the user of which the clicked home](/images/console/collection-override.gif) If you want to override a prop for a specific element within a collection item, pass an override object to `overrideItems`. ```jsx ({ overrides: { Share: { fontWeight: 'bold'}}})} ``` ### Nesting collections Component slots within collections allow you to render additional nested collections. For example, use nested collections to generate a collection of posts, each with its own collection of comments. In this example, you have two collections: `AmpligramCollection` and `CommentViewCollection`. These are bound to the `Post` and `Comment` data models, which have a [one-to-many relationship](/console/data/relationships/). By nesting the `CommentViewCollection` within the `comment` component slot in the `AmpligramCollection`, and using the `overrideItems` prop, you can render each Post with its related Comments. ```jsx import { AmpligramCollection, CommentViewCollection } from './ui-components' function App() { return ( ({ comments: })} /> ); } export default App; ``` ### Add business logic during or after action execution Use the Amplify Hub to listen to actions that are executed via [UI event handlers](/console/uibuilder/eventhandling) and then add your custom business logic. ```jsx import { Hub } from 'aws-amplify' ... Hub.listen("ui", (capsule) => { if (capsule.payload.event === "actions:auth:signout:finished") { // Post-signout logic } }); ``` In the example above, you can add your own custom business logic, when the customer clicks on a "Sign out" button. The Amplify `Hub` provides Studio-generated events on the `ui` channel. The format of action binding Hub events is `actions:[category]:[action_name]:[status]`: | Action name | Description | |---|---| | actions:core:navigate:started | [Navigate action](/console/uibuilder/eventhandling/#bind-ui-to-navigation-actions) started | | actions:core:navigate:finished | [Navigate action](/console/uibuilder/eventhandling/#bind-ui-to-navigation-actions) finished (possibly with errors) | | actions:datastore:create:started | [DataStore create action](/console/uibuilder/eventhandling/#create-a-record-in-database) started | | actions:datastore:create:finished | [DataStore create action](/console/uibuilder/eventhandling/#create-a-record-in-database) finished | | actions:datastore:update:started | [DataStore update action](/console/uibuilder/eventhandling/#update-a-record-from-database) started | | actions:datastore:update:finished | [DataStore update action](/console/uibuilder/eventhandling/#update-a-record-from-database) finished (possibly with errors) | | actions:datastore:delete:started | [DataStore delete action](/console/uibuilder/eventhandling/#delete-a-record-from-database) started | | actions:datastore:delete:finished | [DataStore delete action](/console/uibuilder/eventhandling/#delete-a-record-from-database) finished (possibly with errors) | | actions:auth:signout:started | [SignOut action](/console/uibuilder/eventhandling/#bind-ui-to-sign-out-actions) started | | actions:auth:signout:finished | [SignOut action](/console/uibuilder/eventhandling/#bind-ui-to-sign-out-actions) finished (possibly with errors) | ## Modify generated code You can't directly customize all generated component code, as changes will be overwritten on the next `amplify pull`. However, the following workaround is available if you want to take control of component modifications. 1. Duplicate the generated JSX and TS file inside `ui-components` (e.g. `Ampligram`) 2. Change the name of the files to something else (e.g. `Ampligram2`) and update the function names to match as well. 3. Update `index.js` to include the new export (e.g. `export { default as Ampligram2 } from "./Ampligram2";`) 4. Import the duplicated component wherever you want. The next `amplify pull` will not overwrite this new file. ## Example use cases The following code snippets show how you can handle specific scenarios in your app. ### Add Pagination to a collection ``` import {AmpligramCollection} from './ui-components' ``` ### Make a component responsive Figma components that use *Auto layout* are automatically mapped to responsive React components. However, some components may require further customizations. Use breakpoints to define behavior: ```jsx ``` or ```jsx ``` ### Set hover states on icons The following example shows how to override an icon with a CSS class name.
```jsx // App.css .custom-btn:hover { transform: scale(1.2); } // App.jsx const iconOverrides = { "Button": { className: "custom-btn" } } ``` ![Hover override using class names](/images/console/hover-override.gif)
### Save form data **Note:** Amplify Studio now provides a new experience to build React forms. We recommend you to review [Form Builder (React)](/console/formbuilder/overview) first before using the data action bindings documented below. Amplify Studio provides [data action bindings](/console/uibuilder/eventhandling#bind-ui-to-create-update-or-delete-a-data-record) but if you can also self-manage the form submission states and workflows in code. Get the override keys based on the element name in Studio and then set `onChange` handlers. For example `TextFieldzoh` is the name of the "name input field" component. ![Studio interface showing the form field names](/images/console/form-override.png) ```jsx const [name, setName] = useState(""); const [location, setLocation] = useState(""); const [email, setEmail] = useState(""); const profileOverrides = { "TextFieldzoh": { onChange: (event) => { setName(event.target.value) } }, "TextFieldzwu": { onChange: (event) => { setLocation(event.target.value) } }, "TextFieldsdk": { onChange: (event) => { setEmail(event.target.value) } }, "Button": { onClick: () => alert(`Saving form ${name} ${location} ${email}`) } } return ( ... ... ) ``` ### Navigation from parent to detail views Amplify Studio provides [navigation action bindings](/console/uibuilder/eventhandling/#bind-ui-to-navigation-actions) but if you want to integrate with your own routing system, you can also self-manage the navigation actions. For example, you want to click on an item in a collection to get to detail views. Use the `overrideItems` prop to modify each element's property within a collection. The return value of `overrideItems` will be applied as an override onto the collection item's component. ```jsx ({ style: { cursor: "pointer" }, onClick: () => { // The actual redirect can happen whichever way you want // `item` represent the data item that is passed into the // collection item. In this case, it's a "home". } })} /> ```