# Write a Flow component: one HTML file

> A Flow component is a single HTML file with a Node.js part, a settings form and a design. Build one that changes the text of a message, learn the parts of the file and how to test it.

Framework: flow
Product: Flow (flow@11.1)
Language: en
Content-SHA256: 98e0101ffef81a1e2ff75365737b0c12e754571250c18d5e601aba641db20dff
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: 
Review: not-recorded

A component is **one `.html` file**. Flow reads the file, runs its Node.js part inside the stream and shows its design in the editor. The official components of [the repository](/en/flow/the-components-repository/) all use this format, so you can read any of them as an example.

## An example: `shout.html`

It receives a message, converts the text to upper case, adds a suffix and sends it on.

```html
<script total>

	exports.id = 'shout';
	exports.name = 'Shout';
	exports.group = 'Common';
	exports.version = '1';
	exports.icon = 'ti ti-speakerphone';
	exports.author = 'Forge';
	exports.config = { suffix: '!' };
	exports.inputs = [{ id: 'input', name: 'Input' }];
	exports.outputs = [{ id: 'output', name: 'Output' }];

	exports.make = function(instance, config) {

		let count = 0;

		instance.message = function($) {
			count++;
			instance.status({ shouted: count });
			$.data = String($.data).toUpperCase() + config.suffix;
			$.send('output');
		};

	};

</script>

<settings>
	<div class="padding">
		<ui-component name="input" path="?.suffix" config="maxlength:10">Suffix</ui-component>
	</div>
</settings>

<readme>
The component converts the text of a message to upper case and adds a suffix.
</readme>

<body>
	<header>
		<i class="ICON"></i>NAME
	</header>
	<footer>
		<div class="padding">Shouted: <b><ui-bind path="STATUS.shouted" config="text:value||0"></ui-bind></b></div>
	</footer>
</body>
```

## The parts of the file

| Part | What it is for |
|---|---|
| `<script total>` | the Node.js code of the component, executed in the process of the stream |
| `<settings>` | the form of the configuration, with the components of the user interface (`ui-component`, paths that start with `?.` point to the `config` of the component) |
| `<readme>` | the help shown in the editor |
| `<body>` | the box in the diagram: a `<header>` with the placeholders `ICON` and `NAME`, and optionally a `<footer>` or a body, where `<ui-bind path="STATUS.x">` shows the status and `CONFIG.x` the configuration |
| `<style>` | the CSS of the box; `.CLASS` is replaced with a class unique for the component |
| `<script>` (second) | optional JavaScript of the editor, for buttons in the box (it can send `{ TYPE: 'trigger', id: ... }` to the stream) |

## The `exports` of the Node.js part

| Export | Meaning |
|---|---|
| `id`, `name`, `group`, `version`, `icon`, `author` | the identity of the component and where it appears in the list |
| `config` | the default configuration; the form of `<settings>` edits it |
| `inputs`, `outputs` | the list of `{ id, name }` connectors. A component without `inputs` is a source |
| `kind` | optional: the role of the component in the catalogue (`trigger`, `action` or `output`) |
| `make(instance, config)` | called once per box that you place in the diagram |

## The `instance`

Inside `make` you define the behavior by assigning functions to the instance:

| Function | Called when |
|---|---|
| `instance.message = function($) {}` | a message arrives. `$.data` is the data, `$.send('output')` forwards it to the connectors of that output, `$.destroy()` ends it without sending |
| `instance.configure = function() {}` | the configuration changes, and once at the start |
| `instance.trigger = function() {}` | the button of the editor or the code asks for it |
| `instance.pause = function(is) {}` | the stream is paused or resumed |
| `instance.close = function() {}` | the box is removed or the stream stops: clear your timers here |

And you call `instance.send('output', data)` to create a message of your own (as `timer` does), `instance.status(object)` to show a status in the box (`delay.html` passes a time in milliseconds as a second argument to refresh it) and `instance.throw(error)` to report an error.

## Try it

1. Put `shout.html` in a catalogue and write its address in the setting `components2` (see [the repository](/en/flow/the-components-repository/)), or import a stream that contains it in its `components`.
2. Add a `timer` and a `print` next to it in the editor, connect them and start the stream.
3. Open the status of the box: the counter grows with each message.

To test a component without the editor, the repository has a small tester, see [the components repository](/en/flow/the-components-repository/).
