Make an AS3 Flash Component with Custom UI Controls
I’d nearly given up the whole idea, having searched all over the internet only to find dozens of others asking the same questions I’d had, but no one was delivering the answers. Or not all the answers, at any rate.
As seemingly exhaustive as Adobe’s gigantic article by Jeff Kamerer is, many answers were not to be found there. I wanted to make an SWC-based component that did not rely on the UI Component framework — after all, not every component is a UI gadget! I wanted to write a simple class to draw something to the stage, with a few options I could control with my own control panel and see updated with a live preview right on the stage.
Along the way to a solution, I encountered a host of problems getting the control panel to communicate with the authoring tool, and for the authoring tool to communicate properly with the component and the control panel… and then even with all of those problems cleared up, there was still the problem of parameter settings being retained in the finished compiled product. It seems quite clear that several aspects of component creation do not work as they should–at least not when you add a custom control panel into the mix. However, in spite of all the problems, there is a reasonable workaround to make this possible.
Eventually, after a lot of googling about, and a whole lot of trial and error, I managed to piece together this jigsaw puzzle, and can now present to you a method for creating your very own components with custom control panels, all in Actionscript 3, which works for both Flash CS3 and CS4. In this article, I’ll give you a tour of the code for a simple component and its control panel, with notes on how to make your own components.
CLICK HERE to download the complete source files.
THE COMPONENT
Defining Parameters
First, let’s take a look at the source code for the component. Open up “MyComponent.as” …In order to inform Flash what the parameters for this component will be, we have to include [Inspectable] metadata tags in the class code.
[Inspectable (name = "color", variable = "color", type = "Color", defaultValue = "FF0000")] [Inspectable (name = "radius", variable = "radius", type = "Number", defaultValue = "10")]
I’ve placed them right at the top of the class, for easy reference. Both parameters–radius and color–are going to call getter/setters which you’ll find near the end of the file. There are a few important things to notice here:
- The name and variable for each parameter MUST be the same
- All of the parameters MUST be in alphabetical order
- The default values must be set BOTH in the meta-data and the code
Of course these are hardly official requirements for writing a component, and I’m sure there are plenty of components out there that were not written following these rules. However, in order to create this component with a custom user interface in the Component Inspector and with live preview… all three of these rules must be observed.
Note also that the default value for color is represented as a hex string without the leading “#” or “0x”
The setSize() Method
Moving on, the setSize() method is where we handle resizing of the component. The Flash authoring tool will automatically call this function for live preview, so it must be defined as public, and with parameters for width and height.
public function setSize(w:Number, h:Number):void { _width = w; _height = h; draw(); } private function draw():void { _background.graphics.clear(); _background.graphics.beginFill(_color, 1); _background.graphics.drawRoundRect(0, 0, _width, _height, _radius, _radius); _background.graphics.endFill(); _tf.text = Math.floor(_width) + " x " + Math.floor(_height); _tf.x = (_width - _tf.width) * 0.5; _tf.y = (_height - _tf.height) * 0.5 + 2; }
Some component source examples I’ve come across have defined a draw() method as protected, with a drawNow() method to provide public access. I have found no requirement for this, except perhaps when working with the UIComponent framework.
Parameter get/set functions
Next, the getter/setter functions for our parameters, color and radius. We need to use getter/setter rather than public properties so that whenever these values change, we can redraw the component. This will keep the component updated both for live preview and at runtime.
public function get radius():Number { return _radius; } public function set radius(value:Number):void { _radius = value; draw(); } public function get color():int { return _color; } public function set color(value:int):void { _color = value; draw(); }
Override width and height
Finally, we must override the getter/setter functions for width and height. If we don’t, then when an actionscript call is used to change the dimensions of our component, it would merely be stretched or squashed. What we want is to redraw the component with the new size.
override public function get width():Number { return _width; } override public function set width(value:Number):void { _width = value; draw(); } override public function get height():Number { return _height; } override public function set height(value:Number):void { _height = value; draw(); }
Compile and Test
Let’s compile the component and try it out without any custom control panels, just for starters. Open up “Make a Component.fla” You’ll find just one library item, a MovieClip called “MyComponent.” It’s not quite ready to be compiled as it is. Double-click the item to open it up on the stage. You’ll find just one object, called “avatar” which the component code will use for default dimensions and as a simple means of setting font format properties as well as embedding the font. All right let’s compile…
- In the Library, right click “MyComponent” and click on “Properties”
- Tick the box: “Export for ActionScript” Since the class box will have automatically set itself to “MyComponent” it will use our component code.
- Click OK, and again, right click “MyComponent” in the Library and click on “Component Definition…”
- As redundant as it is, type “MyComponent” into the Class box here also, and then click OK.
- Again, right click “MyComponent” in the Library and click on “Component Definition…”
- Tick the box: “Display in Components Panel” and click OK.
- Now right click “MyComponent” one more time and click on “Export SWC File…”
- Make a new folder in: “C:\Program Files\Adobe\Adobe Flash CS3\en\Configuration\Components” called “My Components” or “Test Components” or whatever you like.
- Export the SWC file to this foler.
- Open up the Components panel (ctrl-F7 /
-F7) - Click the panel options button (the tiny black triangle in the upper right corner of the panel) and click on “Reload”
- You should see the name of the folder you created your component in, so open that and you’ll find your new component.
- Make a new Flash document where we’ll give the component a try out.
- Drag the MyComponent from the Library panel onto the stage. You should see something like this:
- With the component selected, click on the Parameters tab of the Properties panel.
- Try changing the parameter values. Immediately as you change the values, the component updates itself.
- Save this file as “Test Component.fla” and we’ll come back to it later.
NOTE: The parameters part of this dialog will now show our parameters, radius and color. Frankly, this dialog was built backwards: it ought to have filled in the Class from the Properties dialogue, and from that the Parameters. But that’s not how it works. What’s more, don’t bother trying to rearrange your parameters using the buttons provided–those changes will be lost. You see, as soon as you click OK in this dialog, Flash reads in the Class file, searching for meta-data and rebuilds the parameters table…!
NOTE: Whenever you re-compile your SWC file, you must reload the Components panel for Flash to load in the updated version.

Tthe avatar has been replaced. Our component code has been run, right on the stage.
CUSTOM CONTROL PANEL
Something to keep in mind is that our custom control panel will not communicate directly with the component instance. Rather, the control panel adjusts parameter settings in the authoring tool, and the authoring tool in turn modifies the component instance. The component instance receives information via the setSize() method and property setters, and has no means of its own to communicate with either the authoring tool or the control panel. Keeping our parameters in alphabetical order, rather than trying to arrange them in some logical order, allows us to avoid a minefield of problems.
Reading Parameter Values
Let’s have a look at the source code for our control panel. Open up “ControlPanel.as” Once again, right near the top of the file are references to our parameters:
private const PARAMETER_COLOR:String = "fl.getDocumentDOM().selection[0].parameters[0].value"; private const PARAMETER_RADIUS:String = "fl.getDocumentDOM().selection[0].parameters[1].value";
These instructions refer to parts of the Flash authoring tool’s user interface using the JSFL language–specifically, the parameters panel of the selected object. (See below under Further Reading for more details about JSFL.) Notice that the numbering of the parameters follows the alphabetical order we’ve maintained. Although it’s not required to set these constants, it makes the rest of the code considerably more readable.
public function ControlPanel() { color.text = MMExecute(PARAMETER_COLOR); if (color.text.substr(0, 1) != "#") color.text = "#" + dec2hex(uint(color.text)); color.addEventListener(Event.CHANGE, setColorFromText, false, 0, true); colorPicker.addEventListener(ColorPickerEvent.CHANGE, setColor, false, 0, true); radius.text = MMExecute(PARAMETER_RADIUS); radius.addEventListener(Event.CHANGE, setRadiusFromText, false, 0, true); radiusSlider.addEventListener(SliderEvent.CHANGE, setRadius, false, 0, true); addEventListener(Event.ENTER_FRAME, setControls, false, 0, true); } //...................... private function setControls(e:Event):void { setColorFromText(); setRadiusFromText(); removeEventListener(Event.ENTER_FRAME, setControls); }
In the class constructor function, we read the current control panel values and apply them to our controls. Using the MMExecute() function (which is made available by importing the package: adobe.utils.MMExecute) allows us to execute our JSFL code defined in those two constants above.
The slider and the color picker components’ default parameter values will be applied right after our control panel is instantiated. Hence, the code to set those controls had to be called from an ENTER_FRAME event listener, so that it would occur after those components had been initialized.
Setting Parameter Values
Whenever parameters are changed, either with the handy slider & color picker, or with the text fields, setting the parameters in the authoring tool requires another simple call to MMExecute():
MMExecute(PARAMETER_RADIUS + "=" + value); // Which, assuming value is 20, is equivalent to... MMExecute("fl.getDocumentDOM().selection[0].parameters[1].value = 20");
That’s really there is to it. The remainder of the ControlPanel.as code works like any other Flash form, updating text and components to work together, and using l to MMExecute() to update the authoring tool. The authoring tool in turn sets variables in our component instance to update the live preview. Now let’s add this control panel to our component…
Compile the Component with Custom UI
- Compile the control panel (Shift-F12) creating “Component Control Panel.swf”
- Now, re-open “Make a Component.fla” and right-click MyComponent in the Library panel, then click “Component Definition…”
- Across from “Custom UI:” click on the Set button.
- Select “Custom UI in external .swf file”
- Select “Display in Component Inspector panel”
- Assign the Custom UI .swf file by clicking on “Browse…” and selecting ”Component Control Panel.swf” which we just created.
- Click OK
- Click OK
- We’re ready to re-compile the component. Right-click MyComponent and click on “Export SWC File…” and overwrite the older SWC file we created
- Update the Component panel by clicking the panel options button (the tiny black triangle in the upper right corner of the panel) and click on “Reload”
- Re-open your test file: “Test Component.fla”
- Click and drag the updated component from the Coponents panel, into the Library panel. You should see the dialog: “One or more library items already exist in the document.” Select “Replace existing items” to update your test file.
- Now when you click on a component instance on the stage, the Parameters panel will no longer allow parameters to be set there, but will give you a button to launch the Component Inspector, which is where our control panel will appear.
- Try making a few variations of the component on stage and compile your test movie.
NOTE: By choosing “Display in Property Inspector” in step 4, you can get your control panel to appear in the Parameters tab. However, in this example case, the color picker demands more space than is available there.
CONCLUSION
Thanks for reading! I hope you’ve found this tutorial helpful. Check out the file “Use the Component.fla” and its base class “UseComponent.as” for various tests which helped me to refine this method and write this tutorial. There is also an illustration of the one issue, described below, that I have as yet been unable to resolve. If you should come up with a solution, please be sure to post about it here!
Known Issue:
If I rotate the component on the stage in the authoring tool, its width and height are incorrectly reported as an unrotated bounding box, which will inevitably be larger than the correct dimensions, as shown below:

The selected component shows its correct dimensions as 83 x 17, while the authoring tool shows the incorrect dimensions 70.2 x 70.2. At runtime, the component is initialized with those incorrect dimensions:

[UPDATE] A solution to this problem is presented by Juan Carlos in a comment that follows this post.
Further Reading:
Read about the [Inspectable] meta-data tag:
http://livedocs.adobe.com/flex/3/html/help…
http://livedocs.adobe.com/flash/9.0/main/…
It seems this information does pertain to AS3 as compiled by Flash CS3+, but I have never found documentation except as it pertains either to Flex or to AS2.
To find out more about JSFL and what you can do with MMExecute(), take a look at this excellent video by Lee Brimelow about creating panels to extend the Flash IDE:
http://gotoandlearn.com/play?id=66
This reference to extending Flash provides full details of JSFL support in Flash:
http://livedocs.adobe.com/flash/9.0/main/flash_cs3_extending.pdf
…and a tutorial on creating FLA-based components:
http://www.flashbrighton.org/wordpress/?p=31
39 Comments »
RSS feed for comments on this post. TrackBack URL
Very useful, thanks.
One question. I tried to add another property, _label. I added another meta tag for _label. I also commented out the dimensions text and set it to use the _label property instead. Doesn’t seem to work. The textfield doesn’t show anything. Any ideas?
You may need to re-open the “Component Definition” dialog to get Flash to re-examine your list of parameters. Even though you’re not changing anything in that dialog, just open it and click OK. That dialog is really back-to-front: It reads your source code for meta-data tags when you click OK to close the dialog. So if you open it up a second time, you should see that the list of parameters has changed.
Also, be sure as I’ve mentioned to keep your parameters in alphabetical order. The reason for this, is that somewhere along the way Flash alphabetizes the parameters itself. I tried at first to make radius the first parameter, followed by color, and wouldn’t you know, the radius slider ended up changing the color! You’ll want to alphabetize underscore as coming before the letter “A”
I tried something even more simple. I commented out the dimensions text and set it to a hard coded string. Still doesn’t show anything. Interesting.
Oh! Well, the dimensions textfield has just the characters embedded that are needed for showing dimensions: 0123456789x.
To try and undestand how to create cs4 components ive been trying to create my own button component with custom graphics.
Ive gotten so far as to make your example work, with creating graphics via code in the class.
How do I add graphics from flash itself?
Ive tried searched and only found tutorials that seem to be cs3 specific.
is there anyway to add elements to something like a “component assets” folder and get em usable in the component class?
You can create any assets you like in Flash, by adding to the “My Component” MovieClip in “Make a Component.fla” in my example files. Those assets will be compiled into the component… but maybe that’s not what you’d like to do?
There is an alternate technique for making components, which may be more appropriate to your needs: the FLA component method; this tutorial looks at the SWC component method. While the SWC method is all very self-contained, the FLA method allows the user of the component to alter component assets in Flash, to re-skin the component. Is that what you’d like to be able to do?
I forgot to declare my assets in the class.
Thanx, this article (and your responce) has helped me alot.
Glad to hear it!
Thanks a bunch. Got it finally working.
I’m still having an issue however:
. Looking for a work-around. If you have a trick up your sleeve please let me know thx
Flash seems to call the setters after calling the constructor. But it’s in the constructor where i need the user-costumized values
As long as Flash does call your setter functions immediately after the constructor, I’m not sure what problem you’re having. In your constructor, you could apply default values, purely for the sake of initializing your component—Then when Flash calls the setters, the component is modified with user settings. Maybe if you’re having a problem where the default component becomes visible for a split-second before the user settings are applied, you could hold off adding any content to the stage in your constructor—do a quick check in your setters:
if (parent==null) addChild(...)…or something like that.Hopefully this solves it. Let me know what works!
Not quite relevant, but… You can use optional parameters in the constructor to apply custom settings right away… but of course that will only be an option for ActionScript generated instances of the component rather than instances dropped onto the stage in the Flash IDE.
Hey, thanks for this tutorial. I tried your first test: Compile and Test. It worked in CS3 but not in CS4. It seems like CS4 doesn’t recognize the swc file. Tried closing and reopening Flash CS4 didn’t work. I did the tutorial over again and tried on different machines, but with the same result.
Did anybody have this problem?
Hi Terrence,
I’ve just-double checked by compiling the control panel and component in CS3, and then copying the SWC file over to CS4. Works just fine. …and now I realize the problem you’re having: The location for component files has changed in CS4. When I export the SWC file, a file browser always opens up in the correct location. Presumably, for whatever reason, this isn’t the case for you. I believe these are the correct locations for component files for CS4:
Windows Vista:
C:\Users\username\Local Settings\Application Data\Adobe\Flash CS4\language\Configuration\Components
Windows XP:
C:\Documents and Settings\ (Current User) \Local Settings\Application Data\Adobe\Flash CS4\en\Configuration\Components
Mac OS X:
Macintosh HD/Users/userName/Library/Application Support/Adobe/Flash CS4/language/Configuration/Components
…I’ll update the tutorial shortly so nobody else has this issue. Please let me know that this solves the problem for you.
Actually, the above file locations are also applicable to CS3. In fact, technically, they’re probably more appropriate than the location I’ve given in this article. What I don’t like about this file path, at least for WinXP users, is that the Local Settings folder is hidden. So, if you’re having trouble finding it…
* Click on the Tools menu of the explorer window, and Folder Options…
* Click on the View tab
* Look for an item called Hidden files and folders and, if it’s not already expanded, double-click it
* Select Show hidden files and folders
…Oh! And one other issue– it seems you must put your SWC file into a folder (such as “My Components”) at that location (for CS3) otherwise it won’t be seen.
Hey, it was my bad. I was putting the swc file in the CS3 folder, not CS4. Once I managed to put it in the correct folder, it worked perfectly. Again, thanks for your tutorial. It saved me a lot of time and agony
Hello again!
a few comments back i commented having a problem with needing the inspectable values in the constructor while flash is setting them afterwards. As you said you were intrested in my solution if i were to find one so i’m posting it now:
The solution to my problem was to subscribe to an event which will launch after the inspectable values are set. This way I can use the user defined values as if it were in the constructor:
public function World() { //<- constructor
addEventListener(Event.ADDED, onAdd);
}
public function onAdd(e : Event) : void {
//constructor code using inspectable values here
}
On the go i also found a solution to your problem! You’re having troubles with flash giving invalid (or at least unwished) dimensions if you have an object rotated. You can get its real dimensions using my simple method. What it does is setting the rotation to zero. Now it takes and stores the wished dimensions in a Point object. It restores the original rotation of the object and returns the point object.
public function getRealDimensions(dpo:DisplayObject):Point{
var tempRotation:Number = dpo.rotation;
dpo.rotation = 0;
var p:Point = new Point(dpo.width,dpo.height);
dpo.rotation = tempRotation;
return p;
}
@Fejuto:
Thanks for getting back. Actually, I used exactly that method in the control panel. The color picker and slider components would be automatically set with default values from their parameters immediately after the control panel comes to life. So I had to add an event to apply the values after the control panel was constructed. I can’t recall now why I chose to use the ENTER_FRAME event rather than ADDED which would be a better choice. …I should’ve realized that was what you were talking about! That’s something I should’ve addressed in the tutorial, since it’s bound to be a common problem.
As for
getRealDimensions(), yes I think that’s part of the solution. The other part would be to store the correct dimensions as hidden parameters, so that the component can correct itself. I’ll give that a shot when I get a chance.@Terence:
Glad to help!
Seriously you are the bomb
Brilliant tutorial, thanks David, very helpful.
I’m just wondering how to separate the live preview of the component from the functionality of the component. For the live preview I want something very simple (a box that resizes and a centred(but not resized) title), but for the component itself i want something much more complex.
I’ve been playing with using a different class in the Symbol Properties to the Component Definition with not-so-pretty results in the live preview(let alone what it does to parameters).
I also tried the different tack of using the ‘Live Preview’ button in Component Definition to define a preview swf, but again, i’m struggling to get the component to recognise when its resized.
So then I’m wondering if the code itself can detect whether its in live preview mode or actually running. Had my hopes in Capabilities.playerType, but it seems to think its running ‘External’ either way.
Have you tried this yourself? Any tips?
Hi Craig,
I’ll keep looking and post back whenever I do find it; should you find the answer yourself, do let me know.
Glad the tutorial helped! While figuring the whole thing out, I came across a snippet of code that answers your question. I came across the same snippet in a couple of places, in fact. At the time, it wasn’t something I needed, but it seemed pretty easy to find… now where the @$!% it’s gone, I have no idea!
At last! I’ve finally found that simple line of code to answer your question, Craig…
When the component is playing inside the Flash IDE, its parent property reveals the situation. Where it would normally be a MovieClip or the Stage, while in the IDE the parent will be a specialized LivePreviewParent.
@gnfontaine: Glad to help
Fantastic, thanks for that David. It works a treat.
One comment a little off-topic i’d like to make – i’m finding debugging live-preview component code extremely cumbersome and time-consuming. Do you find that?
I had a line of code that the live-preview had problems with that ran fine outside of live-preview. With no feedback as to the location of error, it took a series of code-commenting, outputting a swc, reloading components, etc to determine the source of the problem…
Yup. You can’t just compile and run the thing in a single step; you’ve gotta compile it, then re-load components, then replace it in your test project, and then finally test it out. And if you’re working on the control panel, then you’ve got to compile that before re-compiling the component…
If there’s a trick to avoiding these cumbersome steps, I’m afraid I haven’t found it… yet!
It is actually possible in Flash CS4 to create custom component UI with AS3 that doesn’t require the SWF panel work around. I recently realized this wasn’t actually documented anywhere, so I blogged about it.
Thanks for the heads up, Jeff. Good to know!
I’m thinking that people writing components for sale may prefer to use this workaround, so they don’t have to sell a CS3 version and a CS4 version.
Another technique I’ve been meaning to look into is to use a LocalConnection to allow two-way communication between the component and the control panel. This again should be compatible between CS3 and CS4.
My understanding is that communication via LocalConnection does not work, although I have not tried it myself. Just hearsay.
And I’m afraid that you are right about the method for custom component UI with AS3 only works in CS4 so if such a component is used in CS3 you will have a broken UI. This means you would need to have a separate way of packaging the component for CS3 without the custom UI, or supply a swf panel or something like this.
Thanks a ton buddy! This is very very helpful and step by step tutorial you explained for new comers to build custom components.
Once Again Thank you so much.
You can easily solve the rotation issue in a similar way you handle the width and the height of the component:
– Add a new property in your component class (_rotation).
– In the class constructor add:
_rotation = rotation;
rotation = 0;
before the lines that store the actual width and height.
– Finally update the “draw()” method to “reset” the rotation property:
private function draw():void {
_background.graphics.clear();
_background.graphics.beginFill(_color, 1);
_background.graphics.drawRoundRect(0, 0, _width, _height, _radius, _radius);
_background.graphics.endFill();
_tf.text = Math.floor(_width) + ” x ” + Math.floor(_height);
_tf.x = (_width – _tf.width) * 0.5;
_tf.y = (_height – _tf.height) * 0.5 + 2;
rotation = _rotation;
}
I hope it helps.
Thank you for your excellent tutorial.
Hello, I read the comments and it seems that nobody had a problem I’m having. I was going through the tutorial and on step 17 of the first part “THE COMPONENT”, when I created and tried to compile the “Test Component.fla”, I got the following error:
TypeError: Error #1034: Type Coercion failed: cannot convert MyComponent@2e9ca031 to MyComponent.
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
at TestComponent_fla::MainTimeline()
Because of it I can’t finish the tutorial and the “Use the Component.fla” doesn’t work. I get the same error it it. Do you have any ideas?
Thanks.
@Ksenia:
There’s precious little information about that error in Adobe’s documentation, unfortunately. It seems likely that you’ve simply mis-typed something in whatever code is instantiating the component, ie, var c:MyComponent = new MyComponent() If that’s not it, I’ll be happy to take a look at your project files to help you track down the issue.
@Juan Carlos:
Thank you for posting! Of course! (slaps forehead) Why didn’t I think of it?! I haven’t had a chance to test your code, but I’m fairly sure that will solve it. I’ve gone ahead and added a note a the end of the tutorial to direct others to your post. When I have more time, I’ll eventually update the tutorial and incorporate it into the example project.
@Yatin:
Glad the tutorial was helpful!
Hi, very nice post. I have been wonder’n bout this issue,so thanks for posting
Hi, gr8 post thanks for posting. Information is useful!
Hello. I think the article is really interesting. I am even interested in reading more. How soon will you update your blog?
@Garyk:
Glad you liked it. I’ve been way too tied up with work over the past few months to write new blog posts. Whenever I have to work really hard to find a solution to an issue, as in this case, I make myself a note for a new post… so I’ve got a few lined up, but sadly they’ll have to wait until I’ve got a bit more free time.
@Jane & Katty:
I’m glad it’s helped.
Many thanks for working out this AS3 solution using JSFL for custom UIs! Due to there is really NO comment to be found at adobe.com (nor elsewhere in the web – so far I searched for) about creating custom UIs with AS3 this is a great thing you did! Hopefully adobe will at least ask you if they include your solution into there help files :-).
(ok, I didn’t try your solution by now, but I’m sure that it will work :-))
have you tried sending an array thru this method?
i’ve tried, and it’s not working. i revieve null. maybe i’m wrong somewhere, that’s why i’m asking.
good tutorial btw
I have not used the Array type in component definitions, nor the List type. If that’s not working for you, an acceptable alternative might be to simply use the String type and parse the results yourself. So if the value of a parameter called daysOfWeek is “Sunday,Monday,Tuesday” you can use daysOfWeek.split(“,”) to turn it into an Array.
Glad you like the tutorial!
I would like to know if this can be done completely in actionscript without using the Flash or Flex IDEs. I can’t afford Flash and have been learning and coding in an IDE I found on the web plux mxmlc from the Flex SDK.
It might be a pain to code everything by hand but that’s the way I currently have to code in actionscript.
[...] non-UIComponent solution from David Barlia’s ‘Studio Barliesque’ [...]