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 [`<Collection/>`](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'

<AmpligramCollection isPaginated itemsPerPage={3}/>

```

### 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.

<table>
<tbody>
<tr>
<td>

![override](/images/console/ui-override.png)

</td>
<td>

```jsx
import {FAQItem} from './ui-components'
...
...                //⬇️ Element name shown in Studio
<FAQItem overrides={{"Title": { color: "red" } }}/>
```
</td>
</tr>
</tbody>
</table>

### 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
<HomeCollection overrideItems={({ item, index }) => ({
  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
<HomeCollection overrideItems={(item, index) => ({ 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 (
    <AmpligramCollection overrideItems={({ item, index }) => ({
      comments: <CommentViewCollection items={item.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'

<AmpligramCollection isPaginated itemsPerPage={3}/>

```
### 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
 <NavBar width={{ small: "300px", large: "600px", xl: "800px" }}/>
```

or 

```jsx
 <NavBar width={"100vw"}/>
```

### Set hover states on icons

The following example shows how to override an icon with a CSS class name.

<table>
<tbody>
<tr>
<td>

```jsx
// App.css
.custom-btn:hover {
   transform: scale(1.2);
}

// App.jsx
const iconOverrides = {
  "Button": {
     className: "custom-btn"
  }
}

<HeroLayout1 overrides={iconOverrides} />
```

</td>
<td>

![Hover override using class names](/images/console/hover-override.gif)

</td>
</tr>
</tbody>
</table>


### Save form data

<Callout warning>

**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.

</Callout>

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 (
    ...
    <EditProfile overrides={profileOverrides}/>
    ...
)
```

### 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
<HomeCollection overrideItems={({item, index}) => ({
  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".
  }
})} />
```