> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/gradio-app/gradio/llms.txt
> Use this file to discover all available pages before exploring further.

# Frontend development

> Learn how to build your custom component's user interface with Svelte

This guide will cover everything you need to know to implement your custom component's frontend.

<Tip>
  Gradio components use Svelte. Writing Svelte is fun! If you're not familiar with it, we recommend checking out their interactive [guide](https://learn.svelte.dev/tutorial/welcome-to-svelte).
</Tip>

## The directory structure

The frontend code should have, at minimum, two files:

* `Index.svelte`: This is the main export and where your component's layout and logic should live.
* `Example.svelte`: This is where the example view of the component is defined.

Feel free to add additional files and subdirectories. If you want to export any additional modules, remember to modify the `package.json` file:

```json theme={null}
"exports": {
    ".": "./Index.svelte",
    "./example": "./Example.svelte",
    "./package.json": "./package.json"
},
```

## The Index.svelte file

Your component should expose the following props that will be passed down from the parent Gradio application.

```typescript theme={null}
import type { LoadingStatus } from "@gradio/statustracker";
import type { Gradio } from "@gradio/utils";

export let gradio: Gradio<{
    event_1: never;
    event_2: never;
}>;

export let elem_id = "";
export let elem_classes: string[] = [];
export let scale: number | null = null;
export let min_width: number | undefined = undefined;
export let loading_status: LoadingStatus | undefined = undefined;
export let mode: "static" | "interactive";
```

### Props explained

<AccordionGroup>
  <Accordion title="elem_id and elem_classes">
    Allow Gradio app developers to target your component with custom CSS and JavaScript from the Python `Blocks` class.
  </Accordion>

  <Accordion title="scale and min_width">
    Allow Gradio app developers to control how much space your component takes up in the UI.
  </Accordion>

  <Accordion title="loading_status">
    Used to display a loading status over the component when it is the output of an event.
  </Accordion>

  <Accordion title="mode">
    How the parent Gradio app tells your component whether the `interactive` or `static` version should be displayed.
  </Accordion>

  <Accordion title="gradio">
    The `gradio` object is created by the parent Gradio app. It stores some application-level configuration that will be useful in your component, like internationalization. You must use it to dispatch events from your component.
  </Accordion>
</AccordionGroup>

### Minimal example

A minimal `Index.svelte` file would look like:

```svelte theme={null}
<script lang="ts">
	import type { LoadingStatus } from "@gradio/statustracker";
    import { Block } from "@gradio/atoms";
	import { StatusTracker } from "@gradio/statustracker";
	import type { Gradio } from "@gradio/utils";

	export let gradio: Gradio<{
		event_1: never;
		event_2: never;
	}>;

    export let value = "";
	export let elem_id = "";
	export let elem_classes: string[] = [];
	export let scale: number | null = null;
	export let min_width: number | undefined = undefined;
	export let loading_status: LoadingStatus | undefined = undefined;
    export let mode: "static" | "interactive";
</script>

<Block
	visible={true}
	{elem_id}
	{elem_classes}
	{scale}
	{min_width}
	allow_overflow={false}
	padding={true}
>
	{#if loading_status}
		<StatusTracker
			autoscroll={gradio.autoscroll}
			i18n={gradio.i18n}
			{...loading_status}
		/>
	{/if}
    <p>{value}</p>
</Block>
```

## The Example.svelte file

The `Example.svelte` file should expose the following props:

```typescript theme={null}
export let value: string;
export let type: "gallery" | "table";
export let selected = false;
export let index: number;
```

### Props explained

<AccordionGroup>
  <Accordion title="value">
    The example value that should be displayed.
  </Accordion>

  <Accordion title="type">
    This is a variable that can be either `"gallery"` or `"table"` depending on how the examples are displayed. The `"gallery"` form is used when the examples correspond to a single input component, while the `"table"` form is used when a user has multiple input components, and the examples need to populate all of them.
  </Accordion>

  <Accordion title="selected">
    You can also adjust how the examples are displayed if a user "selects" a particular example by using the `selected` variable.
  </Accordion>

  <Accordion title="index">
    The current index of the selected value.
  </Accordion>
</AccordionGroup>

### Example from Radio component

This is the `Example.svelte` file for the core `Radio` component:

```svelte theme={null}
<script lang="ts">
	export let value: string;
	export let type: "gallery" | "table";
	export let selected = false;
</script>

<div
	class:table={type === "table"}
	class:gallery={type === "gallery"}
	class:selected
>
	{value}
</div>

<style>
	.gallery {
		padding: var(--size-1) var(--size-2);
	}
</style>
```

## Handling files

If your component deals with files, these files **should** be uploaded to the backend server. The `@gradio/client` npm package provides the `upload` and `prepare_files` utility functions to help you do this.

* The `prepare_files` function will convert the browser's `File` datatype to Gradio's internal `FileData` type.
* The `upload` function will upload an array of `FileData` values to the server.

You should use the `FileData` data type in your component to keep track of uploaded files.

### Example: Loading files from input

Here's an example of loading files from an `<input>` element when its value changes:

```svelte theme={null}
<script lang="ts">
    import { upload, prepare_files, type FileData } from "@gradio/client";
    export let root;
    export let value;
    let uploaded_files;

    async function handle_upload(file_data: FileData[]): Promise<void> {
        await tick();
        uploaded_files = await upload(file_data, root);
    }

    async function loadFiles(files: FileList): Promise<void> {
        let _files: File[] = Array.from(files);
        if (!files.length) {
            return;
        }
        if (file_count === "single") {
            _files = [files[0]];
        }
        let file_data = await prepare_files(_files);
        await handle_upload(file_data);
    }

    async function loadFilesFromUpload(e: Event): Promise<void> {
		const target = e.target;

		if (!target.files) return;
		await loadFiles(target.files);
	}
</script>

<input
    type="file"
    on:change={loadFilesFromUpload}
    multiple={true}
/>
```

The component exposes a prop named `root`. This is passed down by the parent Gradio app and it represents the base URL that the files will be uploaded to and fetched from.

### WASM support

For WASM support, you should get the upload function from the `Context` and pass that as the third parameter of the `upload` function:

```typescript theme={null}
<script lang="ts">
    import { getContext } from "svelte";
    const upload_fn = getContext<typeof upload_files>("upload_files");

    async function handle_upload(file_data: FileData[]): Promise<void> {
        await tick();
        await upload(file_data, root, upload_fn);
    }
</script>
```

## Leveraging existing Gradio components

Most of Gradio's frontend components are published on [npm](https://www.npmjs.com/), the JavaScript package repository. This means that you can use them to save yourself time while incorporating common patterns in your component, like uploading files.

For example, the `@gradio/upload` package has `Upload` and `ModifyUpload` components for properly uploading files to the Gradio server. Here is how you can use them to create a user interface to upload and display PDF files:

```svelte theme={null}
<script>
	import { type FileData, Upload, ModifyUpload } from "@gradio/upload";
	import { Empty, UploadText, BlockLabel } from "@gradio/atoms";
</script>

<BlockLabel Icon={File} label={label || "PDF"} />
{#if value === null && interactive}
    <Upload
        filetype="application/pdf"
        on:load={handle_load}
        {root}
        >
        <UploadText type="file" i18n={gradio.i18n} />
    </Upload>
{:else if value !== null}
    {#if interactive}
        <ModifyUpload i18n={gradio.i18n} on:clear={handle_clear}/>
    {/if}
    <iframe title={value.orig_name || "PDF"} src={value.data} height="{height}px" width="100%"></iframe>
{:else}
    <Empty size="large"> <File/> </Empty>	
{/if}
```

You can also combine existing Gradio components to create entirely unique experiences. The possibilities are endless! Please read the documentation on our JavaScript packages [here](https://gradio.app/main/docs/js).

## Matching Gradio core's design system

You can explore our component library via Storybook. You'll be able to interact with our components and see them in their various states.

For those interested in design customization, we provide the CSS variables consisting of our color palette, radii, spacing, and the icons we use - so you can easily match up your custom component with the style of our core components. This Storybook will be regularly updated with any new additions or changes.

[View Storybook](https://gradio.app/main/docs/js/storybook)

## Custom configuration

If you want to make use of the vast Vite ecosystem, you can use the `gradio.config.js` file to configure your component's build process. This allows you to make use of tools like TailwindCSS, mdsvex, and more.

Currently, it is possible to configure the following:

**Vite options:**

* `plugins`: A list of Vite plugins to use.

**Svelte options:**

* `preprocess`: A list of Svelte preprocessors to use.
* `extensions`: A list of file extensions to compile to `.svelte` files.
* `build.target`: The target to build for (see [esbuild docs](https://esbuild.github.io/api/#target)).

The `gradio.config.js` file should be placed in the root of your component's `frontend` directory.

### Example: Vite plugin (TailwindCSS)

Custom components can use Vite plugins to customize the build process. Here we configure [TailwindCSS](https://tailwindcss.com), a utility-first CSS framework. Setup is easiest using the version 4 prerelease:

```bash theme={null}
npm install tailwindcss@next @tailwindcss/vite@next
```

In `gradio.config.js`:

```typescript theme={null}
import tailwindcss from "@tailwindcss/vite";
export default {
    plugins: [tailwindcss()]
};
```

Then create a `style.css` file with the following content:

```css theme={null}
@import "tailwindcss";
```

Import this file into `Index.svelte`. Note that you need to import the CSS file containing `@import` and cannot just use a `<style>` tag:

```svelte theme={null}
<script lang="ts">
[...]
import "./style.css";
[...]
</script>
```

### Example: Svelte options (mdsvex)

In `gradio.config.js` you can also specify some Svelte options to apply to the Svelte compilation. In this example we will add support for [`mdsvex`](https://mdsvex.pngwn.io), a Markdown preprocessor for Svelte.

First, install the `mdsvex` plugin:

```bash theme={null}
npm install mdsvex
```

Then add the following to `gradio.config.js`:

```typescript theme={null}
import { mdsvex } from "mdsvex";

export default {
    svelte: {
        preprocess: [
            mdsvex()
        ],
        extensions: [".svelte", ".svx"]
    }
};
```

Now we can create `mdsvex` documents in our component's `frontend` directory and they will be compiled to `.svelte` files:

```md theme={null}
<!-- HelloWorld.svx -->

<script lang="ts">
    import { Block } from "@gradio/atoms";

    export let title = "Hello World";
</script>

<Block label="Hello World">

# {title}

This is a markdown file.

</Block>
```

We can then use the `HelloWorld.svx` file in our components:

```svelte theme={null}
<script lang="ts">
    import HelloWorld from "./HelloWorld.svx";
</script>

<HelloWorld />
```

## Next steps

You now know how to create delightful frontends for your components!

* See [examples](/custom-components/examples) of custom components in action
* Learn how to [configure](/custom-components/configuration) your component package


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.